Repository
OCA/dms · module folder · Try on Runboat
Module version
Category
Document Management
Folder size
17.27 MB
License
LGPL-3
Application
Yes
Auto-installable
No
Website
https://github.com/OCA/dms
Last tracking update
2026-08-20 11:14:39
Authors
Odoo Community Association (OCA), Tecnativa, MuK IT
Maintainers
Odoo Community Association (OCA), Tecnativa, MuK IT
Committers
root, Víctor Martínez, CarlosRoca13, Weblate, OCA-git-bot, oca-ci, Matteo Mircoli, Houzéfa Abbasbhay, christian-ramos-tecnativa
Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
dms_auto_classification, dms_field, dms_user_role, web_editor_media_dialog_dms
Description
DMS is a module for creating, managing and viewing document files
directly within Odoo. This module is only the basis for an entire
ecosystem of apps that extend and seamlessly integrate with the document
management system.

This module adds portal functionality for directories and files for
allowed users, both portal or internal users. You can get as well a
tokenized link from a directory or a file for sharing it with any
anonymous user.

Code Analysis

Views touched (34)
XML IDNameModelTypeStatus
portal_my_dms My DMS ir.ui.view qweb New
portal_my_dms_breadcrumbs My DMS: Breadcrumbs ir.ui.view qweb Inherits portal.portal_breadcrumbs
portal_my_home_dms Portal My Home : dms entries ir.ui.view qweb Inherits portal.portal_my_home
res_config_settings_view_form res.config.settings.view.form.inherit.dms res.config.settings form Inherits base.res_config_settings_view_form
search_dms_directory dms_directory.search dms.directory search New
search_dms_file dms_file.search dms.file search New
search_dms_file_migration dms_file.search dms.file search New
view_dms_access_groups_form dms_access.group.form dms.access.group form New
view_dms_access_groups_tree dms_access_groups.list dms.access.group list New
view_dms_category_form dms_category.form dms.category form New
view_dms_category_search dms_category.search dms.category search New
view_dms_category_tree dms_category.list dms.category list New
view_dms_directory_form dms_directory.form dms.directory form New
view_dms_directory_kanban dms_directory.kanban dms.directory kanban New
view_dms_directory_new_form dms_directory.form dms.directory form Inherits view_dms_directory_form
view_dms_directory_tree dms_directory.list dms.directory list New
view_dms_file_form dms_file.form dms.file form New
view_dms_file_graph dms_file.graph dms.file graph New
view_dms_file_kanban dms_file.kanban dms.file kanban New
view_dms_file_kanban_wizard_selection dms_file.kanban.wizard.selection dms.file kanban Inherits dms.view_dms_file_kanban
view_dms_file_migration_tree dms_file.list dms.file list New
view_dms_file_new_form dms_file.form dms.file form Inherits view_dms_file_form
view_dms_file_pivot dms_file.pivot dms.file pivot New
view_dms_file_tree dms_file.list dms.file list New
view_dms_storage_form dms_storage.form dms.storage form New
view_dms_storage_new_form dms_storage.form dms.storage form Inherits view_dms_storage_form
view_dms_storage_search dms_storage.search dms.storage search New
view_dms_storage_tree dms_storage.list dms.storage list New
view_dms_tag_form dms_tag.form dms.tag form New
view_dms_tag_kanban dms_tag.kanban dms.tag kanban New
view_dms_tag_search dms_tag.search dms.tag search New
view_dms_tag_tree dms_tag.list dms.tag list New
wizard_dms_file_move_form_view wizard.dms.file.move.form wizard.dms.file.move form New
wizard_dms_share_form wizard.dms.share.form wizard.dms.share form Inherits portal.portal_share_wizard
HTTP endpoints (5)
Route(s)HandlerAuthTypeMethodsFlags
/my/dms CustomerPortal.portal_my_dms user http ALL website
/my/dms/directory/<int:dms_directory_id> CustomerPortal.portal_my_dms_directory public http ALL sudo website
/my/dms/file/<int:dms_file_id>/download CustomerPortal.portal_my_dms_file_download public http ALL sudo website
/config/dms.forbidden_extensions OnboardingController.forbidden_extensions user json ALL sudo
/web/binary/upload_dms_file OnboardingController.upload_dms_file user http ALL
Models touched (19)

New fields (7)
  • category_id Many2one → dms.category
    comodel_name='dms.category' context={'dms_category_show_path': True} string='Category'
  • color Integer
    default=0
  • company_id Many2one → res.company
    comodel_name='res.company' index='btree' readonly=True related='storage_id.company_id' store=True string='Company'
  • is_hidden Boolean
    readonly=True related='storage_id.is_hidden' store=True string='Storage is Hidden'
  • name Char
    index='btree' required=True
  • storage_id Many2one → dms.storage
    comodel_name='dms.storage' copy=True store=True string='Storage'
  • storage_id_save_type Selection
    related='storage_id.save_type' store=False
Public methods (1)
  • search_panel_select_range(self, field_name, **kwargs)
    @api.model
    Add context to display short folder name.

New fields (0)

No new fields.

Public methods (1)
  • unlink(self)
    Cascade DMS related resources removal. Avoid executing in ir.* models (ir.mode, ir.model.fields, etc), in transient models and in the models we want to check.

New fields (17)
  • child_group_ids One2many → dms.access.group
    comodel_name='dms.access.group' inverse_name='parent_group_id' string='Child Groups'
  • complete_directory_ids Many2many → dms.directory
    auto_join=True column1='gid' column2='aid' comodel_name='dms.directory' readonly=True relation='dms_directory_complete_groups_rel' string='Complete directories'
  • count_directories Integer
    compute='_compute_count_directories'
  • count_users Integer
    compute='_compute_users' store=True
  • directory_ids Many2many → dms.directory
    auto_join=True column1='gid' column2='aid' comodel_name='dms.directory' readonly=True relation='dms_directory_groups_rel' string='Directories'
  • explicit_user_ids Many2many → res.users
    column1='gid' column2='uid' comodel_name='res.users' relation='dms_access_group_explicit_users_rel' string='Explicit Users'
  • group_ids Many2many → res.groups
    column1='gid' column2='rid' comodel_name='res.groups' relation='dms_access_group_groups_rel' string='Groups'
  • name Char
    required=True string='Group Name' translate=True
  • parent_group_id Many2one → dms.access.group
    comodel_name='dms.access.group' index='btree' ondelete='cascade' string='Parent Group'
  • parent_path Char
    index='btree'
  • perm_create Boolean
    string='Create Access'
  • perm_inclusive_create Boolean
    compute='_compute_inclusive_permissions' recursive=True store=True string='Inherited Create Access'
  • perm_inclusive_unlink Boolean
    compute='_compute_inclusive_permissions' recursive=True store=True string='Inherited Unlink Access'
  • perm_inclusive_write Boolean
    compute='_compute_inclusive_permissions' recursive=True store=True string='Inherited Write Access'
  • perm_unlink Boolean
    string='Unlink Access'
  • perm_write Boolean
    string='Write Access'
  • users Many2many → res.users
    auto_join=True column1='gid' column2='uid' comodel_name='res.users' compute='_compute_users' recursive=True relation='dms_access_group_users_rel' store=True string='Group Users'
Public methods (2)
  • copy_data(self, default=None)
  • default_get(self, fields_list)
    @api.model

New fields (13)
  • active Boolean
    default=True help='The active field allows you to hide the category without removing it.'
  • child_category_ids One2many → dms.category
    comodel_name='dms.category' inverse_name='parent_id' string='Child Categories'
  • complete_name Char
    compute='_compute_complete_name' recursive=True store=True
  • count_categories Integer
    compute='_compute_count_categories' string='Count Subcategories'
  • count_directories Integer
    compute='_compute_count_directories'
  • count_files Integer
    compute='_compute_count_files'
  • count_tags Integer
    compute='_compute_count_tags'
  • directory_ids One2many → dms.directory
    comodel_name='dms.directory' inverse_name='category_id' readonly=True string='Directories'
  • file_ids One2many → dms.file
    comodel_name='dms.file' inverse_name='category_id' readonly=True string='Files'
  • name Char
    required=True translate=True
  • parent_id Many2one → dms.category
    comodel_name='dms.category' index='btree' ondelete='cascade' string='Parent Category'
  • parent_path Char
    index='btree'
  • tag_ids One2many → dms.tag
    comodel_name='dms.tag' inverse_name='category_id' string='Tags'
Public methods (0)

No public methods.

New fields (29)
  • alias_process Selection
    default='directory' help=' Define how incoming emails are processed:\n\n - Single Files: The email gets attached to the directory and\n all attachments are created as files.\n\n - Subdirectory: A new subdirectory is created for each email\n and the mail is attached to this subdirectory. The attachments\n are created as files of the subdirectory.\n ' required=True selection=[('files', 'Single Files'), ('directory', 'Subdirectory')] string='Unpack Emails as'
  • allowed_model_ids Many2many → ir.model
    comodel_name='ir.model' related='storage_id.model_ids'
  • child_directory_ids One2many → dms.directory
    auto_join=False comodel_name='dms.directory' copy=True inverse_name='parent_id' string='Subdirectories'
  • complete_group_ids Many2many → dms.access.group
    column1='aid' column2='gid' comodel_name='dms.access.group' compute='_compute_groups' compute_sudo=True readonly=True recursive=True relation='dms_directory_complete_groups_rel' store=True string='Complete Groups'
  • complete_name Char
    compute='_compute_complete_name' recursive=True store=True
  • count_directories Integer
    compute='_compute_count_directories' string='Count Subdirectories Title'
  • count_directories_title Char
    compute='_compute_count_directories' string='Count Subdirectories'
  • count_elements Integer
    compute='_compute_count_elements'
  • count_files Integer
    compute='_compute_count_files' string='Count Files Title'
  • count_files_title Char
    compute='_compute_count_files' string='Count Files'
  • count_total_directories Integer
    compute='_compute_count_total_directories' string='Total Subdirectories'
  • count_total_elements Integer
    compute='_compute_count_total_elements' string='Total Elements'
  • count_total_files Integer
    compute='_compute_count_total_files' string='Total Files'
  • file_ids One2many → dms.file
    auto_join=False comodel_name='dms.file' copy=True inverse_name='directory_id' string='Files'
  • group_ids Many2many → dms.access.group
    column1='aid' column2='gid' comodel_name='dms.access.group' relation='dms_directory_groups_rel' string='Groups'
  • human_size Char
    compute='_compute_human_size' string='Size (human readable)'
  • inherit_group_ids Boolean
    default=True string='Inherit Groups'
  • is_root_directory Boolean
    default=False help='Indicates if the directory is a root directory.\n A root directory has a settings object, while a directory with a set\n parent inherits the settings form its parent.'
  • model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_model_id' domain="[('id', 'in', allowed_model_ids)]" inverse='_inverse_model_id' store=True string='Model'
  • parent_id Many2one → dms.directory
    comodel_name='dms.directory' compute='_compute_parent_id' copy=True default=<expr> domain="[('permission_create', '=', True)]" index='btree' ondelete='restrict' prefetch=False readonly=False store=True string='Parent Directory'
  • parent_path Char
    index='btree'
  • root_directory_id Many2one → dms.directory
    compute='_compute_root_id' store=True args: 'dms.directory', 'Root Directory'
  • size Float
    compute='_compute_size'
  • starred Boolean
    compute='_compute_starred' inverse='_inverse_starred' search='_search_starred'
  • storage_id Many2one → dms.storage
    auto_join=True comodel_name='dms.storage' compute='_compute_storage_id' compute_sudo=True ondelete='restrict' readonly=False store=True string='Storage'
  • storage_id_inherit_access_from_parent_record Boolean
    related='storage_id.inherit_access_from_parent_record' related_sudo=True store=True
  • storage_id_save_type Selection
    prefetch=False readonly=True related='storage_id.save_type' related_sudo=True store=False
  • tag_ids Many2many → dms.tag
    column1='did' column2='tid' comodel_name='dms.tag' compute='_compute_tags' domain="[\n '|', ['category_id', '=', False],\n ['category_id', 'child_of', category_id]]\n " readonly=False relation='dms_directory_tag_rel' store=True string='Tags'
  • user_star_ids Many2many → res.users
    column1='did' column2='uid' comodel_name='res.users' relation='dms_directory_star_rel' string='Stars'
Public methods (13)
  • action_dms_directories_all_directory(self)
  • action_dms_files_all_directory(self)
  • action_save_onboarding_directory_step(self)
  • check_access_token(self, access_token=False)
  • copy_data(self, default=None)
  • create(self, vals_list)
    @api.model_create_multi
  • message_new(self, msg_dict, custom_values=None)
    @api.model
  • message_update(self, msg_dict, update_vals=None)
  • search_panel_select_multi_range(self, field_name, **kwargs)
    @api.model
  • search_panel_select_range(self, field_name, **kwargs)
    @api.model
  • toggle_starred(self)
  • unlink(self)
    Custom cascade unlink. Cannot rely on DB backend's cascade because subfolder and subfile unlinks must check custom permissions implementation.
  • write(self, vals)

New fields (25)
  • active Boolean
    default=True help='If a file is set to archived, it is not displayed, but still exists.' string='Archived'
  • attachment_id Many2one → ir.attachment
    comodel_name='ir.attachment' index=True ondelete='cascade' prefetch=False string='Attachment File'
  • checksum Char
    index='btree' readonly=True string='Checksum/SHA1'
  • content Binary
    attachment=False compute='_compute_content' inverse='_inverse_content' prefetch=False required=True store=False
  • content_binary Binary
    attachment=False prefetch=False
  • content_file Binary
    attachment=True prefetch=False
  • directory_id Many2one → dms.directory
    auto_join=True comodel_name='dms.directory' context={'dms_directory_show_path': True} domain="[('permission_create', '=', True)]" index='btree' ondelete='restrict' required=True string='Directory' tracking=True
  • extension Char
    compute='_compute_extension' readonly=True store=True
  • human_size Char
    compute='_compute_human_size' readonly=True store=True string='Size (human readable)'
  • image_1920 Image
    compute='_compute_image_1920' readonly=False store=True
  • is_lock_editor Boolean
    compute='_compute_locked' string='Editor'
  • is_locked Boolean
    compute='_compute_locked' string='Locked'
  • locked_by Many2one → res.users
    comodel_name='res.users'
  • migration Char
    compute='_compute_migration' compute_sudo=True prefetch=False readonly=True store=True string='Migration Status'
  • mimetype Char
    compute='_compute_mimetype' readonly=True store=True string='Type'
  • path_json Text
    compute='_compute_path' compute_sudo=True readonly=True store=False
  • path_names Char
    compute='_compute_path' compute_sudo=True readonly=True store=False
  • require_migration Boolean
    compute='_compute_migration' compute_sudo=True store=True
  • res_id Integer
    related='directory_id.res_id' string='Linked attachments record ID'
  • res_model Char
    related='directory_id.res_model' string='Linked attachments model'
  • root_directory_id Many2one
    related='directory_id.root_directory_id'
  • save_type Char
    compute='_compute_save_type' prefetch=False string='Current Save Type'
  • size Float
    readonly=True
  • storage_id Many2one
    prefetch=False readonly=True related='directory_id.storage_id'
  • tag_ids Many2many → dms.tag
    column1='fid' column2='tid' comodel_name='dms.tag' domain="['|', ('category_id', '=', False),('category_id', '=?', category_id)]" relation='dms_file_tag_rel' string='Tags'
Public methods (13)
  • action_migrate(self, should_logging=True)
  • action_save_onboarding_file_step(self)
  • action_wizard_dms_file_move(self)
  • check_access(self, operation)
  • check_access_token(self, access_token=False)
  • copy_data(self, default=None)
  • create(self, vals_list)
    @api.model_create_multi
  • get_human_size(self)
  • lock(self)
  • search_panel_select_multi_range(self, field_name, **kwargs)
    @api.model
  • search_panel_select_range(self, field_name, **kwargs)
    @api.model
    This method is overwritten to make it 'similar' to v13. The goal is that the directory searchpanel shows all directories (even if some folders have no files).
  • unlink(self)
  • unlock(self)

New fields (1)
  • icon_url Char
    compute='_compute_icon_url' string='Icon URL'
Public methods (0)

No public methods.

New fields (7)
  • permission_create Boolean
    compute='_compute_permissions' search='_search_permission_create' string='Create Access'
  • permission_read Boolean
    compute='_compute_permissions' search='_search_permission_read' string='Read Access'
  • permission_unlink Boolean
    compute='_compute_permissions' search='_search_permission_unlink' string='Delete Access'
  • permission_write Boolean
    compute='_compute_permissions' search='_search_permission_write' string='Write Access'
  • record_ref Reference
    compute='_compute_record_ref' selection=<expr> string='Record Referenced'
  • res_id Integer
    index='btree' store=True string='Linked attachments record ID'
  • res_model Char
    index='btree' store=True string='Linked attachments model'
Public methods (4)
  • create(self, vals_list)
    @api.model_create_multi
  • filtered_domain(self, domain)
    This method is needed to inhibit the behavior when called from the _check_access() method with sudo() https://github.com/odoo/odoo/blob/fc737a147b9aefbd6ae5d111835ce3f4f7b4240a/odoo/models.py#L4465. It would cause the error that multiple records are not accessed to be displayed. The _filtered_access() method is also overwritten to prevent this sudo() specific behavior and to be able to access only the appropriate records.
  • unlink(self)
  • write(self, vals)

New fields (13)
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> help='If set, directories and files will only be available for the selected company.' string='Company'
  • count_storage_directories Integer
    compute='_compute_count_storage_directories' string='Count Directories'
  • count_storage_files Integer
    compute='_compute_count_storage_files' string='Count Files'
  • include_message_attachments Boolean
    default=False help='Indicate if directories and files auto-create in mail composition process too' string='Create files from message attachments'
  • inherit_access_from_parent_record Boolean
    default=False help='Indicate if directories and files access work only with related model access (for example, if some directories are related with any sale, only users with read access to these sale can access)' string='Inherit permissions from related record'
  • is_hidden Boolean
    default=False help='Indicates if directories and files are hidden by default.' string='Storage is Hidden'
  • model Char
    search='_search_model' store=False
  • model_ids Many2many → ir.model
    string='Linked Models' args: 'ir.model'
  • name Char
    required=True
  • root_directory_ids One2many → dms.directory
    auto_join=False comodel_name='dms.directory' copy=False inverse_name='storage_id' readonly=False string='Root Directories'
  • save_type Selection
    default='database' help='The save type is used to determine how a file is saved by the system. If you change this setting, you can migrate existing files manually by triggering the action.' required=True selection=[('database', 'Database'), ('file', 'Filestore'), ('attachment', 'Attachment')]
  • storage_directory_ids One2many → dms.directory
    auto_join=False comodel_name='dms.directory' copy=False inverse_name='storage_id' readonly=True string='Directories'
  • storage_file_ids One2many → dms.file
    auto_join=False comodel_name='dms.file' copy=False inverse_name='storage_id' readonly=True string='Files'
Public methods (3)
  • action_save_onboarding_storage_step(self)
  • action_storage_migrate(self)
  • write(self, values)

New fields (8)
  • active Boolean
    default=True help='The active field allows you to hide the tag without removing it.'
  • category_id Many2one → dms.category
    comodel_name='dms.category' context={'dms_category_show_path': True} ondelete='set null' string='Category'
  • color Integer
    default=10 string='Color Index'
  • count_directories Integer
    compute='_compute_count_directories'
  • count_files Integer
    compute='_compute_count_files'
  • directory_ids Many2many → dms.directory
    column1='tid' column2='did' comodel_name='dms.directory' readonly=True relation='dms_directory_tag_rel' string='Directories'
  • file_ids Many2many → dms.file
    column1='tid' column2='fid' comodel_name='dms.file' readonly=True relation='dms_file_tag_rel' string='Files'
  • name Char
    required=True translate=True
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (3)
  • create(self, vals_list)
    @api.model_create_multi
  • unlink(self)
  • write(self, vals)

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • action_close_panel_dms_file(self)
    @api.model

New fields (0)

No new fields.

Public methods (3)
  • action_open_documents_onboarding_directory(self)
    @api.model
    Open the form to create a new directory from the onboarding panel.
  • action_open_documents_onboarding_file(self)
    @api.model
    Open the form to create a new file from the onboarding panel.
  • action_open_documents_onboarding_storage(self)
    @api.model
    Open the form to create a new storage from the onboarding panel.

New fields (4)
  • documents_onboarding_directory_state Selection
    default='not_done' selection=[('not_done', 'Not done'), ('just_done', 'Just done'), ('done', 'Done'), ('closed', 'Closed')]
  • documents_onboarding_file_state Selection
    default='not_done' selection=[('not_done', 'Not done'), ('just_done', 'Just done'), ('done', 'Done'), ('closed', 'Closed')]
  • documents_onboarding_state Selection
    default='not_done' selection=[('not_done', 'Not done'), ('just_done', 'Just done'), ('done', 'Done'), ('closed', 'Closed')]
  • documents_onboarding_storage_state Selection
    default='not_done' selection=[('not_done', 'Not done'), ('just_done', 'Just done'), ('done', 'Done'), ('closed', 'Closed')]
Public methods (3)
  • action_close_documents_onboarding(self)
    @api.model
  • get_and_update_documents_onboarding_state(self)
  • set_onboarding_step_done(self, step)

New fields (2)
  • documents_binary_max_size Integer
    config_parameter='dms.binary_max_size' help='Defines the maximum upload size in MB. Default (25MB)' string='Size'
  • documents_forbidden_extensions Char
    config_parameter='dms.forbidden_extensions' help="Defines a list of forbidden file extensions. (Example: 'exe,msi')" string='Extensions'
Public methods (0)

No public methods.

New fields (2)
  • count_files Integer
    readonly=True
  • directory_id Many2one → dms.directory
    comodel_name='dms.directory' required=True string='Directory'
Public methods (2)
  • default_get(self, fields)
    @api.model
  • process(self)

New fields (0)

No new fields.

Public methods (0)

No public methods.

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Status
Open migration PR — not merged yet for this version
CI status
green — ready to merge
Open since
100 days ago
Last activity
0 days ago
Repository
OCA/dms
Pull request
[19.0][MIG] dms: Migration to 19.0 (#475)