Why Most Companies Outgrow Shared Drives Before They Realize It
Every growing company eventually hits the same wall: vendor contracts live in someone's inbox, expense receipts sit in a Dropbox folder nobody remembers sharing, and the latest version of the employee handbook exists on three different Google Drives with three different names. The information is technically stored — but finding it, acting on it, and controlling who sees it becomes a full-time job.
The Documents module in Odoo 19 is not just a file storage system. It is a centralized digital asset management platform that connects directly to your accounting, HR, project management, and procurement workflows. Documents are tagged, indexed, searchable, and — most importantly — actionable. Upload a vendor bill and a workflow action can automatically create a draft journal entry, assign it to the AP team, and tag it for the correct expense category.
This guide walks through the entire module: workspace architecture, tag taxonomies, automated workflow actions, OCR digitization, spreadsheet integration, share links, access control, and deep integrations with Accounting, HR, and Project. Every configuration uses real Odoo 19 field names, menu paths, and Python model references.
Workspaces and Folders: Designing Your Document Architecture
Workspaces are the top-level organizational unit in the Documents module. Navigate to Documents → Configuration → Workspaces to manage them. Each workspace acts as an isolated container with its own tag structure, access rules, and default workflow actions. Think of workspaces as departments — Finance, Human Resources, Legal, Projects — while folders within workspaces mirror your internal filing structure.
The underlying model is documents.folder (renamed from documents.share in earlier versions). Key fields include name, parent_folder_id (for nesting), company_id, group_ids (access groups), read_group_ids, tag_ids (available tags), and action_ids (workflow actions available in this workspace). The description field supports HTML and appears as a helper tooltip when users browse the workspace.
A well-designed workspace hierarchy keeps documents discoverable without forcing users to remember exact file names. Here is a recommended structure for a mid-size company:
<odoo>
<data noupdate="1">
<!-- Top-level workspaces -->
<record id="workspace_finance" model="documents.folder">
<field name="name">Finance</field>
<field name="company_id" ref="base.main_company"/>
<field name="group_ids" eval="[(4, ref('account.group_account_user'))]"/>
<field name="description"><![CDATA[
Vendor bills, customer invoices, bank statements,
and tax documents. OCR digitization is enabled.
]]></field>
</record>
<!-- Nested folder: Vendor Bills -->
<record id="folder_vendor_bills" model="documents.folder">
<field name="name">Vendor Bills</field>
<field name="parent_folder_id" ref="workspace_finance"/>
<field name="description">Scanned and emailed vendor invoices</field>
</record>
<!-- Nested folder: Bank Statements -->
<record id="folder_bank_statements" model="documents.folder">
<field name="name">Bank Statements</field>
<field name="parent_folder_id" ref="workspace_finance"/>
</record>
<!-- HR workspace -->
<record id="workspace_hr" model="documents.folder">
<field name="name">Human Resources</field>
<field name="company_id" ref="base.main_company"/>
<field name="group_ids" eval="[(4, ref('hr.group_hr_user'))]"/>
</record>
<!-- Legal workspace -->
<record id="workspace_legal" model="documents.folder">
<field name="name">Legal & Compliance</field>
<field name="company_id" ref="base.main_company"/>
</record>
</data>
</odoo> Both use the same documents.folder model. A workspace is simply a folder with no parent (parent_folder_id = False). It appears in the left sidebar of the Documents app. A folder with a parent appears as a sub-item. Access rights cascade downward — a user who can access the Finance workspace automatically has access to Vendor Bills and Bank Statements unless explicitly restricted.
Workflow Actions: Turning Documents into Business Transactions
Workflow actions are the core feature that separates Odoo Documents from a generic file manager. Navigate to Documents → Configuration → Actions to create them. The underlying model is documents.workflow.action (linked to documents.workflow.rule for conditions). When a user selects a document and clicks an action button, Odoo executes a chain of operations: setting tags, moving to a folder, creating a linked business record, or running custom Python code.
Each action defines: a domain (which documents it appears on, based on tags, workspace, or MIME type), an action type (set tags, move folder, create record, run server action), and optional chained actions that execute sequentially. The domain field uses Odoo's standard domain syntax.
from odoo import models, fields, api
class DocumentWorkflowCreateBill(models.Model):
_inherit = 'documents.document'
def action_create_vendor_bill(self):
"""Workflow action: create account.move from uploaded document."""
self.ensure_one()
AccountMove = self.env['account.move']
bill_vals = {
'move_type': 'in_invoice',
'partner_id': self._guess_partner_from_content(),
'invoice_date': fields.Date.today(),
'ref': self.name,
}
bill = AccountMove.create(bill_vals)
# Attach the document file to the new bill
self.env['ir.attachment'].create({
'name': self.name,
'datas': self.datas,
'res_model': 'account.move',
'res_id': bill.id,
'mimetype': self.mimetype,
})
# Update document metadata
self.write({
'res_model': 'account.move',
'res_id': bill.id,
'tag_ids': [(4, self.env.ref(
'custom_documents.tag_invoice_processed'
).id)],
})
return {
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'res_id': bill.id,
'views': [(False, 'form')],
}
def _guess_partner_from_content(self):
"""Attempt to match document name or OCR text to a vendor."""
Partner = self.env['res.partner'].sudo()
if self.partner_id:
return self.partner_id.id
# Fallback: search by document name tokens
tokens = (self.name or '').replace('-', ' ').split()
for token in tokens:
if len(token) > 3:
match = Partner.search(
[('name', 'ilike', token),
('supplier_rank', '>', 0)],
limit=1,
)
if match:
return match.id
return FalseBuilt-in workflow action types available in Odoo 19 without custom code:
| Action Type | What It Does | Common Use Case |
|---|---|---|
| Set Tags | Adds or removes tags from selected documents | Mark a batch of invoices as "Approved" with one click |
| Move to Folder | Relocates documents to a target workspace/folder | Move processed bills from "Inbox" to "Archived" |
| Create Vendor Bill | Generates account.move with type in_invoice | One-click bill creation from scanned PDF |
| Create Task | Generates project.task linked to the document | Turn a requirements doc into an actionable task |
| Request Signature | Sends document to Sign module for e-signature | Route contracts for approval without leaving Documents |
| Create Spreadsheet | Converts CSV/XLSX to an Odoo Spreadsheet document | Analyze uploaded data directly in the browser |
Workflow actions work on multi-select. In the Documents Kanban view, select 50 scanned receipts with Shift+Click, then click "Create Vendor Bill" — Odoo will create 50 draft bills in one operation. Each bill links back to its source document via the res_model / res_id fields on documents.document. This bidirectional link means you can always trace a journal entry back to the original scan.
Spreadsheet Integration: Live Data Analysis Inside Your Document Workspace
Odoo 19 includes a full-featured spreadsheet engine accessible directly from the Documents module. Navigate to any workspace, click New → Spreadsheet, and you get a browser-based spreadsheet that supports formulas, pivot tables, charts, and — critically — live data from any Odoo model.
The spreadsheet is stored as a documents.document record with handler = 'spreadsheet' and the data persisted in the spreadsheet_data JSON field. The spreadsheet_snapshot field stores periodic snapshots for version history. Key menu path: Documents → [Workspace] → New → Spreadsheet.
The real power is the Insert Data feature. From within a spreadsheet, click Data → Insert Pivot or Data → Insert List to pull live data from any Odoo model. For example, insert a pivot of account.move.line grouped by account_id and date to build a real-time P&L report that updates every time the spreadsheet is opened. You can also insert individual cell references using the =ODOO.PIVOT() and =ODOO.LIST() functions.
Key spreadsheet functions available in Odoo 19:
| Function | Syntax | Description |
|---|---|---|
| ODOO.PIVOT | =ODOO.PIVOT(pivot_id, measure, ...) | Returns a value from a pivot table defined in the spreadsheet |
| ODOO.PIVOT.HEADER | =ODOO.PIVOT.HEADER(pivot_id, ...) | Returns the header label for a pivot group |
| ODOO.LIST | =ODOO.LIST(list_id, index, field) | Returns a field value from a list data source at a given row index |
| ODOO.HYPERLINK | =ODOO.HYPERLINK(url, label) | Creates a clickable link to an Odoo record or external URL |
Spreadsheets stored in the Documents module inherit the workspace's access controls. A financial model in the Finance workspace is automatically restricted to users with accounting access. You can share a read-only snapshot via a share link without granting access to the underlying Odoo data — the shared version contains static values, not live queries.
A practical example: the CFO creates a spreadsheet in the Finance workspace with a pivot of account.move.line grouped by account_id.code (rows) and date:month (columns), measuring balance. This produces a real-time trial balance that updates on every page refresh. Add a chart on top of the pivot, and you have a live financial dashboard — no BI tool required, no data export, no stale CSV. The spreadsheet can be bookmarked, shared with the board via a time-limited link, and versioned automatically through the Documents module's snapshot system.
Digitization and OCR: Extracting Structured Data from Scanned Documents
The digitization feature (powered by Odoo's IAP OCR service) automatically extracts structured data from uploaded documents. When you upload a PDF or image to a workspace with digitization enabled, Odoo sends it to the OCR endpoint and populates fields like partner_id, invoice_date, total_amount, and individual line items — without any manual data entry.
Enable digitization at Documents → Configuration → Settings → Digitization. The setting documents.digitization_mode controls behavior: manual (user clicks "Digitize"), auto_send (uploaded files are sent immediately), or disabled. OCR credits are consumed from your Odoo IAP account — each document costs approximately one credit.
Supported document types for OCR extraction:
| Document Type | Extracted Fields | Target Model |
|---|---|---|
| Vendor Bills | Vendor name, invoice number, date, due date, line items, taxes, total | account.move |
| Expense Receipts | Merchant, date, amount, currency, payment method | hr.expense |
| ID Documents | Full name, document number, expiry date, nationality | hr.employee |
from odoo import models, api
class DocumentAutoDigitize(models.Model):
_inherit = 'documents.document'
@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
finance_folder = self.env.ref(
'custom_documents.workspace_finance',
raise_if_not_found=False,
)
for doc in records:
if (
doc.folder_id == finance_folder
and doc.mimetype in ('application/pdf', 'image/jpeg', 'image/png')
and not doc.res_model # not already linked to a record
):
doc.action_send_for_digitization()
return recordsOCR accuracy improves dramatically with consistent vendors. After the first invoice from a vendor is manually verified, Odoo's AI learns the layout. Subsequent invoices from the same vendor are extracted with significantly higher accuracy. For best results, correct OCR mistakes in the first 5-10 invoices per vendor — the system adapts its extraction template over time.
Deep Integrations: Accounting, HR, Project, and Custom Models
The Documents module connects bidirectionally with other Odoo apps via bridge modules. When installed, these bridges automatically centralize documents from their respective apps into the Documents workspace. Each bridge is a separate module that can be independently installed.
| Bridge Module | Technical Name | What It Does |
|---|---|---|
| Accounting | documents_account | Vendor bills and attachments sync to Finance workspace. Workflow actions create account.move records. |
| HR | documents_hr | Employee documents (contracts, payslips, ID copies) centralized in HR workspace with per-employee filtering. |
| Project | documents_project | Project attachments appear in a dedicated workspace. Create tasks directly from documents. |
| Sign | documents_sign | Send documents for e-signature directly from the Documents UI. Signed copies auto-return to workspace. |
| Spreadsheet | documents_spreadsheet | Browser-based spreadsheets stored as documents with live Odoo data connections. |
{
'name': 'Custom Documents Configuration',
'version': '19.0.1.0.0',
'category': 'Document Management',
'depends': [
'documents',
'documents_account', # Accounting bridge
'documents_hr', # HR bridge
'documents_project', # Project bridge
'documents_sign', # E-signature bridge
'documents_spreadsheet',# Spreadsheet engine
],
'data': [
'data/documents_workspace.xml',
'data/documents_tags.xml',
'data/documents_workflow_actions.xml',
],
'installable': True,
'auto_install': False,
'license': 'OEEL-1',
} When documents_account is installed, every attachment uploaded to a vendor bill or customer invoice is automatically copied to the configured Finance workspace. The sync is controlled by settings at Accounting → Configuration → Settings → Documents, where you set the target folder_id and default tags. The same pattern applies to documents_hr (payslips sync to HR workspace) and documents_project (task attachments sync to Project workspace).
Storage Management
Document storage in Odoo 19 can be configured at Settings → Technical → Database Structure → Attachments (developer mode). The ir.attachment model supports three storage backends: db (PostgreSQL large objects — default), file (local filesystem at --data-dir), and s3 (Amazon S3 or compatible object storage via the attachment_s3 community module). For production deployments with more than 10,000 documents, we recommend filesystem or S3 storage to keep the database size manageable and backups fast.
Monitor storage usage at Documents → Configuration → Storage. This dashboard shows total storage consumed per workspace, file type distribution, and storage growth trends. Set up a scheduled action (ir.cron) to archive documents older than a retention period:
<odoo>
<data noupdate="1">
<record id="cron_archive_old_documents" model="ir.cron">
<field name="name">Documents: Archive Old Files</field>
<field name="model_id" ref="documents.model_documents_document"/>
<field name="state">code</field>
<field name="code">
from dateutil.relativedelta import relativedelta
cutoff = datetime.date.today() - relativedelta(years=2)
old_docs = env['documents.document'].search([
('create_date', '<=', str(cutoff)),
('active', '=', True),
('tag_ids.name', '=', 'Archived'),
])
archive_folder = env.ref(
'custom_documents.folder_cold_storage',
raise_if_not_found=False,
)
if archive_folder and old_docs:
old_docs.write({
'folder_id': archive_folder.id,
'active': False,
})
</field>
<field name="interval_number">1</field>
<field name="interval_type">weeks</field>
<field name="numbercall">-1</field>
<field name="active">True</field>
</record>
</data>
</odoo> This scheduled action runs weekly, finds all documents tagged "Archived" that are older than two years, and moves them to a cold storage folder while deactivating them. Deactivated documents (active = False) are excluded from normal searches but remain accessible through the "Archived" filter in the Documents interface. This keeps the active document list fast and focused while preserving compliance records indefinitely.
3 Documents Module Mistakes That Lead to Lost Files and Broken Workflows
Flat Workspace Structure Creates Tag Soup
Companies that dump everything into a single "General" workspace and rely exclusively on tags for organization hit a wall around 5,000 documents. The tag filter panel becomes unusable with 40+ tags, search results return hundreds of irrelevant matches, and users revert to asking colleagues "where is that file?" — the exact problem the module was supposed to solve.
Design workspaces around business functions (Finance, HR, Legal, Projects) and folders around document flows (Inbox, Under Review, Approved, Archived). Use tags for cross-cutting concerns (priority, fiscal year, department). This three-dimensional organization — workspace, folder, tags — scales to hundreds of thousands of documents.
OCR Credits Burn Through Silently on Auto-Send Mode
Setting digitization_mode = auto_send means every uploaded file — including screenshots, internal memos, and duplicate scans — consumes an OCR credit. We have seen clients burn through 500 credits in a week because employees were uploading photos of whiteboards and casual screenshots into the Finance workspace. At approximately EUR 0.04 per credit, this adds up fast on high-volume workspaces.
Use auto_send only on workspaces where the vast majority of uploads are actual invoices or receipts (e.g., the Vendor Bills folder). Set all other workspaces to manual mode. Add a domain filter on the auto-digitize logic to check mimetype = 'application/pdf' before sending — this skips images and Office documents that are rarely vendor bills.
Bridge Module Sync Creates Duplicate Attachments
When documents_account is installed, attachments on account.move records are copied to the Finance workspace — not moved. This means the file exists in two places: as an ir.attachment on the invoice and as a documents.document in the workspace. Both reference the same binary data (no actual storage duplication), but users see "two copies" and get confused about which one to update. Worse, deleting the document from the workspace does not delete the attachment from the invoice, and vice versa.
Educate users that the Documents workspace is the single source of truth. The attachment on the invoice is a convenience copy for context. Set up a naming convention (e.g., "INV-2026-0042_scan.pdf") so both copies are identifiable. If storage size is a concern, note that Odoo deduplicates binary data via checksum — two records pointing to identical file content share the same physical storage.
The Business Impact of Centralized Document Management in Odoo 19
Companies that migrate from shared drives and email attachments to Odoo Documents see measurable improvements within the first quarter:
Faceted search with workspace scoping replaces manual folder browsing. Users find documents in seconds instead of minutes, eliminating the "where is that file?" conversations that interrupt teams daily.
OCR extraction + one-click bill creation eliminates manual data entry. For a company processing 200 bills/month, that is 40 hours of accounting time reclaimed — nearly a full week of work every month.
Every document action is logged: who uploaded, tagged, moved, shared, and linked each file. This complete chain of custody satisfies SOC 2 and ISO 27001 evidence requirements without additional tooling.
Beyond efficiency: having documents live inside the ERP means they participate in the same permission model, backup schedule, and retention policy as your business data. No more "the contract was in the marketing manager's personal Dropbox and they left the company."
Optimization Metadata
Complete guide to the Odoo 19 Documents module. Configure workspaces, tags, OCR digitization, workflow actions, spreadsheet integration, share links, and deep accounting/HR bridges.
1. "Workspaces and Folders: Designing Your Document Architecture"
2. "Workflow Actions: Turning Documents into Business Transactions"
3. "Digitization and OCR: Extracting Structured Data from Scanned Documents"
4. "3 Documents Module Mistakes That Lead to Lost Files and Broken Workflows"