From f0f92cf4837fd53c7adab8dd9515d2239ac9163f Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Thu, 28 Sep 2023 16:44:08 -0400 Subject: [PATCH] started on module bemade_document_versions. --- bemade_document_versions/__init__.py | 2 + bemade_document_versions/__manifest__.py | 31 ++++++++ .../data/document_revision_data.xml | 12 ++++ bemade_document_versions/models/__init__.py | 3 + bemade_document_versions/models/document.py | 70 +++++++++++++++++++ .../models/document_revision.py | 23 ++++++ .../models/document_revision_sequence.py | 11 +++ .../wizard/document_revision_wizard.py | 19 +++++ .../data/mail_templates.xml | 11 +++ bemade_project_documents/models/document.py | 1 + .../wizard/request_approvals_wizard.py | 19 ++++- .../wizard/request_approvals_wizard.xml | 17 +++-- 12 files changed, 207 insertions(+), 12 deletions(-) create mode 100644 bemade_document_versions/__init__.py create mode 100644 bemade_document_versions/__manifest__.py create mode 100644 bemade_document_versions/data/document_revision_data.xml create mode 100644 bemade_document_versions/models/__init__.py create mode 100644 bemade_document_versions/models/document.py create mode 100644 bemade_document_versions/models/document_revision.py create mode 100644 bemade_document_versions/models/document_revision_sequence.py create mode 100644 bemade_document_versions/wizard/document_revision_wizard.py create mode 100644 bemade_project_documents/data/mail_templates.xml diff --git a/bemade_document_versions/__init__.py b/bemade_document_versions/__init__.py new file mode 100644 index 0000000..899bcc9 --- /dev/null +++ b/bemade_document_versions/__init__.py @@ -0,0 +1,2 @@ +from . import models + diff --git a/bemade_document_versions/__manifest__.py b/bemade_document_versions/__manifest__.py new file mode 100644 index 0000000..20d23ae --- /dev/null +++ b/bemade_document_versions/__manifest__.py @@ -0,0 +1,31 @@ +# +# Bemade Inc. +# +# Copyright (C) September 2023 Bemade Inc. (). +# Author: Marc Durepos (Contact : marc@bemade.org) +# +# This program is under the terms of the Odoo Proprietary License v1.0 (OPL-1) +# It is forbidden to publish, distribute, sublicense, or sell copies of the Software +# or modified copies of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +{ + 'name': 'Document Versions', + 'version': '15.0.1.0.0', + 'summary': 'Adds document revisions alongside Documents', + 'category': 'Document Management', + 'author': 'Bemade Inc.', + 'website': 'https://www.bemade.org', + 'license': 'OPL-1', + 'depends': ['documents', 'mail'], + 'data': [], + 'installable': True, + 'auto_install': False, +} diff --git a/bemade_document_versions/data/document_revision_data.xml b/bemade_document_versions/data/document_revision_data.xml new file mode 100644 index 0000000..1de5b39 --- /dev/null +++ b/bemade_document_versions/data/document_revision_data.xml @@ -0,0 +1,12 @@ + + + + + Default Document Revision Sequence + document.revision + standard + DOC/ + 2 + + + \ No newline at end of file diff --git a/bemade_document_versions/models/__init__.py b/bemade_document_versions/models/__init__.py new file mode 100644 index 0000000..69e0c5b --- /dev/null +++ b/bemade_document_versions/models/__init__.py @@ -0,0 +1,3 @@ +from . import document_revision +from . import document +from . import document_sequence diff --git a/bemade_document_versions/models/document.py b/bemade_document_versions/models/document.py new file mode 100644 index 0000000..0e6684c --- /dev/null +++ b/bemade_document_versions/models/document.py @@ -0,0 +1,70 @@ +from odoo import models, fields, _, api, Command +from odoo.exceptions import ValidationError + + +class Document(models.Model): + _inherit = ['documents.document'] + + current_revision_id = fields.Many2one('documents.revision', 'Current Revision') + revision_ids = fields.One2many('documents.revision', 'document_id') + revision_sequence = fields.Many2one('documents.revision.sequence', 'document_id', + 'Revision Sequence', ) + track_revisions = fields.Boolean(default=False) + # set copy=False for number_next + number_next = fields.Integer(string='Next Number', required=True, default=1, + copy=False, help="Next number of this sequence") + + @api.constrains('revision_ids', 'revision_sequence', 'track_revisions') + def constrain_revisions(self): + for rec in self: + revision_fields = [rec.revision_ids, rec.revision_sequence, + rec.track_revisions] + if any(revision_fields) and not all(revision_fields): + raise ValidationError(_('A revision sequence must be selected to track' + ' revisions.')) + + def write(self, vals): + super().write(vals) + if self.track_revisions and 'track_revisions' in vals \ + and not vals['track_revisions']: + raise ValidationError(_('Revision tracking cannot be disabled after it has' + 'been turned on for a document.')) + self._check_revision_fields() + + @api.model_create_multi + def create(self, vals): + res = super().create(vals) + for rec in res: + rec._check_revision_fields() + return res + + def _check_revision_fields(self): + """ Helper method to check that all three fields `track_revisions`, + `revisions_sequence` and `revision_ids` are properly set if any one of them is set. + :return: None + """ + self.ensure_one() + revision_fields = [self.revision_ids, self.revision_sequence, + self.track_revisions] + if any(revision_fields) and not all(revision_fields): + self._set_up_revisions() + + def _set_up_revisions(self): + """ + Helper method to set up revisions, no matter how we got into tracking them. + :return: None + """ + self.ensure_one() + self.track_revisions = True # may already be true, but no matter + self.revision_sequence = self.revision_sequence or self.env.ref( + 'bemade_document_versions.document_revision_sequence_default') + self.revision_ids = self.revision_ids or Command.set( + [self._create_first_revision()]) + + def _create_first_revision(self): + """ + Creates a new documents.revision record to associate to this Document + :return: a single, new documents.revision record + """ + self.ensure_one() + return self.env['documents.revision'].create({'document_id': self.id, }) diff --git a/bemade_document_versions/models/document_revision.py b/bemade_document_versions/models/document_revision.py new file mode 100644 index 0000000..70f333f --- /dev/null +++ b/bemade_document_versions/models/document_revision.py @@ -0,0 +1,23 @@ +from odoo import models, fields, _, api + + +class DocumentRevision(models.Model): + _name = "documents.revision" + _description = "Document Revision" + + document_id = fields.Many2one('documents.document', required=True) + attachment_id = fields.Many2one('ir.attachment', required=True) + previous_revision_id = fields.Many2one('documents.revision', 'Previous Revision') + next_revision_id = fields.One2many('documents.revision', 'previous_revision_id') + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + for rec in res: + # When we create a new revision, we need to replace the attachment linked + # to the document to keep it on the latest version. + rec.document_id.attachment_id = rec.attachment_id + # Then we update the current revision to this new revision and link + # back to the previous revisions + rec.previous_revision_id = rec.document_id.current_revision_id + rec.document_id.current_revision_id = rec diff --git a/bemade_document_versions/models/document_revision_sequence.py b/bemade_document_versions/models/document_revision_sequence.py new file mode 100644 index 0000000..167d645 --- /dev/null +++ b/bemade_document_versions/models/document_revision_sequence.py @@ -0,0 +1,11 @@ +from odoo import models, fields, api, _ + + +class DocumentRevisionSequence(models.Model): + """ Creates an independent sequence for each Document when the document is set to + track + """ + _name = 'documents.revision.sequence' + _inherit = 'ir.sequence' + + document_id = fields.Many2one('documents.document', 'Document', ondelete='cascade') \ No newline at end of file diff --git a/bemade_document_versions/wizard/document_revision_wizard.py b/bemade_document_versions/wizard/document_revision_wizard.py new file mode 100644 index 0000000..13a4995 --- /dev/null +++ b/bemade_document_versions/wizard/document_revision_wizard.py @@ -0,0 +1,19 @@ +from odoo import models, fields, _ +from odoo.exceptions import UserError + + +class DocumentRevisionWizard(models.TransientModel): + _name = 'documents.revision.wizard' + _description = 'Allows the creation of new document revisions' + + document_id = fields.Many2one('documents.document', 'Document') + file = fields.Binary('File to upload') + revision_name = fields.Char() + + def default_get(self, fields_list): + ctx = self._context + if 'active_ids' in ctx and len(ctx.get('active_ids')) > 1: + raise UserError(_('You can only create revisions for one document at a time.')) + if 'active_id' not in ctx: + raise UserError(_('You must select a document for which you are creating a revision.')) + self.document_id = self.env['documents.document'].browse(ctx.get('active_id')) diff --git a/bemade_project_documents/data/mail_templates.xml b/bemade_project_documents/data/mail_templates.xml new file mode 100644 index 0000000..bdf8bc1 --- /dev/null +++ b/bemade_project_documents/data/mail_templates.xml @@ -0,0 +1,11 @@ + + + + + Document Approval Request + + Document Approval Request {{ object.name != False and ': ' + object.name or '' }} + {{ }} + + + \ No newline at end of file diff --git a/bemade_project_documents/models/document.py b/bemade_project_documents/models/document.py index 2133ae6..3da1943 100644 --- a/bemade_project_documents/models/document.py +++ b/bemade_project_documents/models/document.py @@ -5,3 +5,4 @@ class Document(models.Model): _inherit = 'documents.document' external_approver_ids = fields.Many2many('res.partner') + diff --git a/bemade_project_documents/wizard/request_approvals_wizard.py b/bemade_project_documents/wizard/request_approvals_wizard.py index 65153a0..d6c5024 100644 --- a/bemade_project_documents/wizard/request_approvals_wizard.py +++ b/bemade_project_documents/wizard/request_approvals_wizard.py @@ -1,11 +1,24 @@ -from odoo import models, fields, api +from odoo import models, fields, api, _ +from odoo.exceptions import ValidationError class RequestDocumentApprovalsWizard(models.TransientModel): _name = 'project_documents.approval.wizard' document_ids = fields.Many2many('documents.document', string='Documents') - partner_ids = fields.Many2many('res.partner') + partner_ids = fields.Many2many('res.partner', string="Recipients", + help="""Contacts who will receive a request to + approve the document.""") + request_template = fields.Many2one('mail.template') + + def default_get(self, fields_list): + if 'request_template' not in fields_list: + self.request_template = self.env.ref() def request_approvals(self): - pass \ No newline at end of file + self._validate_partners_have_emails() + + def _validate_partners_have_emails(self): + for wizard in self: + if any([not p.email for p in wizard.partner_ids]): + raise ValidationError(_('Each partner must have an email address.')) diff --git a/bemade_project_documents/wizard/request_approvals_wizard.xml b/bemade_project_documents/wizard/request_approvals_wizard.xml index 6fcd1da..0c89a8c 100644 --- a/bemade_project_documents/wizard/request_approvals_wizard.xml +++ b/bemade_project_documents/wizard/request_approvals_wizard.xml @@ -15,21 +15,17 @@ project_documents.approval.wizard
- - +