Files
enterprise-addons/documents_project/models/project_project.py
T

176 lines
8.3 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo.tools import _, frozendict
class ProjectProject(models.Model):
_name = 'project.project'
_inherit = ['project.project']
documents_folder_id = fields.Many2one(
'documents.document', string="Documents Folder", copy=False, context=lambda env: {
'default_folder_id': env.company.documents_project_folder_id.id,
},
domain="[('type', '=', 'folder'), ('shortcut_document_id', '=', False), "
"'|', ('company_id', '=', False), ('company_id', '=', company_id)]",
index='btree_not_null',
help="Folder in which all of the documents of this project will be categorized.")
document_count = fields.Integer(
compute='_compute_documents', export_string_translation=False)
document_ids = fields.One2many('documents.document', compute='_compute_documents', export_string_translation=False)
@api.ondelete(at_uninstall=False)
def _archive_folder_on_projects_unlinked(self):
""" Archives the project folder if all its related projects are unlinked. """
self.env['documents.document'].sudo().search([
('project_ids', '!=', False),
('project_ids', 'not any', [('id', 'not in', self.ids)]
)]).sudo(False)._filtered_access('unlink').action_archive()
@api.constrains('documents_folder_id')
def _check_company_is_folders_company(self):
for project in self.filtered('documents_folder_id'):
if folder := project['documents_folder_id']:
if folder.company_id and project.company_id != folder.company_id:
raise UserError(_(
'The "%(folder)s" folder should either be in the "%(company)s" company like this'
' project or be open to all companies.',
folder=folder.name, company=project.company_id.name)
)
def _compute_documents(self):
documents = self.env['documents.document'].search([
('type', 'in', ('binary', 'url')),
('id', 'child_of', self.documents_folder_id.ids)
])
for project in self:
if not project.documents_folder_id:
project.document_ids = self.env['documents.document']
project.document_count = 0
continue
document_ids = documents.filtered(lambda doc: doc.parent_path.startswith(project.documents_folder_id.parent_path))
project.document_ids = document_ids
project.document_count = len(document_ids)
def _create_missing_folders(self):
folders_to_create_vals = []
projects_with_folder_to_create = []
documents_project_folder_id = self.env.company.documents_project_folder_id.id
for project in self:
if not project.documents_folder_id:
folder_vals = {
'access_internal': 'edit' if project.privacy_visibility in ['employees', 'portal'] else 'none',
'company_id': project.company_id.id,
'folder_id': documents_project_folder_id,
'name': project.name,
'type': 'folder',
}
folders_to_create_vals.append(folder_vals)
projects_with_folder_to_create.append(project)
if folders_to_create_vals:
created_folders = self.env['documents.document'].sudo().create(folders_to_create_vals)
for project, folder in zip(projects_with_folder_to_create, created_folders):
project.sudo().documents_folder_id = folder
@api.model_create_multi
def create(self, vals_list):
projects = super().create(vals_list)
if not self.env.context.get('no_create_folder'):
projects._create_missing_folders()
return projects
def write(self, vals):
if 'company_id' in vals:
for project in self:
if project.documents_folder_id and project.documents_folder_id.company_id and len(project.documents_folder_id.project_ids) > 1:
other_projects = project.documents_folder_id.project_ids - self
if other_projects and other_projects.company_id.id != vals['company_id']:
lines = [f"- {project.name}" for project in other_projects]
raise UserError(_(
'You cannot change the company of this project, because its folder is linked to the other following projects that are still in the "%(other_company)s" company:\n%(other_folders)s\n\n'
'Please update the company of all projects so that they remain in the same company as their folder, or leave the company of the "%(folder)s" folder blank.',
other_company=other_projects.company_id.name, other_folders='\n'.join(lines), folder=project.documents_folder_id.name))
if 'name' in vals:
projects = self.filtered(
lambda p: (
(folder := p.documents_folder_id.sudo())
and len(folder.project_ids) == 1
and p.name == folder.name
)
)
projects.documents_folder_id.sudo().name = vals['name']
if new_visibility := vals.get('privacy_visibility'):
(self.documents_folder_id | self.document_ids).action_update_access_rights(
access_internal='none' if new_visibility == 'followers' else 'edit')
project_root_documents = self.env['documents.document']
if 'documents_folder_id' in vals:
project_root_documents = self.documents_folder_id.children_ids
res = super().write(vals)
if 'company_id' in vals:
for project in self:
if project.documents_folder_id and project.documents_folder_id.company_id:
project.documents_folder_id.company_id = project.company_id
if not self.env.context.get('no_create_folder'):
self._create_missing_folders()
if project_root_documents:
project_root_documents.folder_id = self.documents_folder_id
return res
def copy(self, default=None):
# We have to add no_create_folder=True to the context, otherwise a folder
# will be automatically created during the call to create.
copied_projects = super(ProjectProject, self.with_context(no_create_folder=True)).copy(default).with_env(self.env)
for old_project, new_project in zip(self, copied_projects):
if not self.env.context.get('no_create_folder') and old_project.documents_folder_id:
new_project.documents_folder_id = old_project.documents_folder_id.sudo().copy(
{'name': new_project.name, 'owner_id': False}
)
return copied_projects
def _get_stat_buttons(self):
buttons = super()._get_stat_buttons()
if self.documents_folder_id.user_permission != 'none':
buttons.append({
'icon': 'file-text-o',
'text': self.env._('Documents'),
'number': self.document_count,
'action_type': 'object',
'action': 'action_view_documents_project',
'additional_context': json.dumps({
'active_id': self.id,
}),
'sequence': 20,
})
return buttons
def action_view_documents_project(self):
self.ensure_one()
action = self.documents_folder_id.get_formview_action()
if action['tag'] != 'display_notification':
action['context'] |= {
'active_id': self.id,
'active_model': 'project.project',
}
return action
def create_template_from_project_undo_callback(self, callbacks):
super().create_template_from_project_undo_callback(callbacks)
if self.documents_folder_id and callbacks.get("unarchive_project"):
self.documents_folder_id.action_unarchive()
def _get_template_from_project_undo_callbacks(self):
callbacks = super()._get_template_from_project_undo_callbacks()
if self.documents_folder_id and callbacks.get("unarchive_project"):
self.documents_folder_id.action_archive()
return callbacks