diff --git a/README.md b/README.md index ea3734c210..c548606ba1 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Available addons addon | version | maintainers | summary --- | --- | --- | --- [base_cancel_confirm](base_cancel_confirm/) | 19.0.1.0.1 | kittiu | Base Cancel Confirm +[base_revision](base_revision/) | 19.0.1.0.0 | | Keep track of revised document [base_search_custom_field_filter](base_search_custom_field_filter/) | 19.0.1.0.0 | pedrobaeza | Add custom filters for fields via UI [base_substate](base_substate/) | 19.0.1.0.1 | | Base Sub State [base_technical_features](base_technical_features/) | 19.0.1.0.0 | | Access to technical features without activating debug mode diff --git a/base_revision/README.rst b/base_revision/README.rst new file mode 100644 index 0000000000..c8e8fb72b0 --- /dev/null +++ b/base_revision/README.rst @@ -0,0 +1,123 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================== +Base Revision (abstract) +======================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d0e2197d0bb40144298439edb54c8636a285e61001bef3f78798e30200526314 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--ux-lightgray.png?logo=github + :target: https://github.com/OCA/server-ux/tree/19.0/base_revision + :alt: OCA/server-ux +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-ux-19-0/server-ux-19-0-base_revision + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-ux&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Making revision(s) of a document is a common need across many area. + +This module does not provide a functionality by itself but an abstract +model to implement revision capality in other models (e.g. purchase +orders, sales orders, budgets, expenses...). + +**Note:** To be able to use this module in a new model you will need +some development. + +See `sale_order_revision `__ as an +example of implementation. + +Example with sale_order_revision installed, + +On a cancelled orders, you can click on the "New copy of Quotation" +button. This will create a new revision of the quotation, with the same +base number and a '-revno' suffix appended. A message is added in the +chatter saying that a new revision was created. + +In the form view, a new tab is added that lists the previous revisions, +with the date they were made obsolete and the user who performed the +action. + +The old revisions of a sale order are flagged as inactive, so they don't +clutter up searches. + +**Special Remarks:** Starting on version 14, this module was splitted +from sale_order_revision to, + +- base_revision +- sale_order_revision + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Agile Business Group +* Dreambits +* Camptocamp +* Akretion +* Serpent Consulting Services Pvt. Ltd. +* Ecosoft + +Contributors +------------ + +- Devang Pipaliya +- Lorenzo Battistini +- Raphael Valyi +- Alexandre Fayolle +- Serpent Consulting Services Pvt. Ltd. +- Akim Juillerat +- Raf Ven +- Jeroen Evens +- Kitti U. + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/server-ux `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_revision/__init__.py b/base_revision/__init__.py new file mode 100644 index 0000000000..cb45f2710a --- /dev/null +++ b/base_revision/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/base_revision/__manifest__.py b/base_revision/__manifest__.py new file mode 100644 index 0000000000..2d6d4c60fa --- /dev/null +++ b/base_revision/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2013 Agile Business Group sagl () +# Copyright 2016 Serpent Consulting Services Pvt. Ltd. +# Copyright 2018 Dreambits Technologies Pvt. Ltd. () +# Copyright 2020 Ecosoft Co., Ltd. () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Base Revision (abstract)", + "summary": "Keep track of revised document", + "version": "19.0.1.0.0", + "category": "Tools", + "author": "Agile Business Group," + "Dreambits," + "Camptocamp," + "Akretion," + "Serpent Consulting Services Pvt. Ltd.," + "Ecosoft," + "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/server-ux", + "license": "AGPL-3", + "depends": ["base"], + "installable": True, +} diff --git a/base_revision/i18n/base_revision.pot b/base_revision/i18n/base_revision.pot new file mode 100644 index 0000000000..47e5396e43 --- /dev/null +++ b/base_revision/i18n/base_revision.pot @@ -0,0 +1,87 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_revision +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__active +msgid "Active" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__current_revision_id +msgid "Current revision" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__display_name +msgid "Display Name" +msgstr "" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +msgid "Document Revision (abstract)" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__has_old_revisions +msgid "Has Old Revisions" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__id +msgid "ID" +msgstr "" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New Revisions" +msgstr "" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created from: %s" +msgstr "" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created: %s" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__old_revision_ids +msgid "Old revisions" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__unrevisioned_name +msgid "Original Reference" +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_count +msgid "Previous versions count" +msgstr "" + +#. module: base_revision +#: model:ir.model.constraint,message:base_revision.constraint_base_revision_revision_unique +msgid "Reference and revision must be unique." +msgstr "" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_number +msgid "Revision" +msgstr "" diff --git a/base_revision/i18n/es.po b/base_revision/i18n/es.po new file mode 100644 index 0000000000..2bf9ec656d --- /dev/null +++ b/base_revision/i18n/es.po @@ -0,0 +1,84 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_revision +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-02-23 09:21+0000\n" +"PO-Revision-Date: 2022-02-23 10:22+0100\n" +"Last-Translator: Ana Suárez \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Poedit 2.3\n" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__active +msgid "Active" +msgstr "Activo" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__current_revision_id +msgid "Current revision" +msgstr "Revisión actual" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +msgid "Document Revision (abstract)" +msgstr "Revisión Documento (resumen)" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__has_old_revisions +msgid "Has Old Revisions" +msgstr "Tiene revisiones antiguas" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New Revisions" +msgstr "Nuevas revisiones" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created: %s" +msgstr "Nueva revisión creada: %s" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__old_revision_ids +msgid "Old revisions" +msgstr "Revisiones antiguas" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__unrevisioned_name +msgid "Original Reference" +msgstr "Referencia original" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_count +msgid "Previous versions count" +msgstr "Nº de versiones anteriores" + +#. module: base_revision +#: model:ir.model.constraint,message:base_revision.constraint_base_revision_revision_unique +msgid "Reference and revision must be unique." +msgstr "Referencia y revisión deben ser únicas." + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_number +msgid "Revision" +msgstr "Revisión" + +#~ msgid "Display Name" +#~ msgstr "Nombre mostrado" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Última modificación el" diff --git a/base_revision/i18n/it.po b/base_revision/i18n/it.po new file mode 100644 index 0000000000..533b673303 --- /dev/null +++ b/base_revision/i18n/it.po @@ -0,0 +1,74 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_revision +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-03-25 12:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.2\n" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__active +msgid "Active" +msgstr "Attiva" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__current_revision_id +msgid "Current revision" +msgstr "Revisione corrente" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +msgid "Document Revision (abstract)" +msgstr "Revisione documento (sintesi)" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__has_old_revisions +msgid "Has Old Revisions" +msgstr "Ha revisioni precedenti" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New Revisions" +msgstr "Nuove revisioni" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created: %s" +msgstr "Nuova revisione creata: %s" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__old_revision_ids +msgid "Old revisions" +msgstr "Revisioni precedenti" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__unrevisioned_name +msgid "Original Reference" +msgstr "Riferimento originale" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_count +msgid "Previous versions count" +msgstr "Conteggio versioni precedenti" + +#. module: base_revision +#: model:ir.model.constraint,message:base_revision.constraint_base_revision_revision_unique +msgid "Reference and revision must be unique." +msgstr "Il riferimento e la revisione devono essere univoci." + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_number +msgid "Revision" +msgstr "Revisione" diff --git a/base_revision/i18n/pt.po b/base_revision/i18n/pt.po new file mode 100644 index 0000000000..5ba9e45505 --- /dev/null +++ b/base_revision/i18n/pt.po @@ -0,0 +1,74 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_revision +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-03-07 19:06+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.10.2\n" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__active +msgid "Active" +msgstr "Ativa" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__current_revision_id +msgid "Current revision" +msgstr "Revisão atual" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +msgid "Document Revision (abstract)" +msgstr "Revisão do Documento (abstrato)" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__has_old_revisions +msgid "Has Old Revisions" +msgstr "Tem Antigas Revisões" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New Revisions" +msgstr "Novas Revisões" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created: %s" +msgstr "Nova revisão criada: %s" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__old_revision_ids +msgid "Old revisions" +msgstr "Revisões antigas" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__unrevisioned_name +msgid "Original Reference" +msgstr "Referência Original" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_count +msgid "Previous versions count" +msgstr "Nº de versões anteriores" + +#. module: base_revision +#: model:ir.model.constraint,message:base_revision.constraint_base_revision_revision_unique +msgid "Reference and revision must be unique." +msgstr "A referência e a revisão devem devem ser únicas." + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_number +msgid "Revision" +msgstr "Revisão" diff --git a/base_revision/i18n/tr.po b/base_revision/i18n/tr.po new file mode 100644 index 0000000000..a36f2ecee2 --- /dev/null +++ b/base_revision/i18n/tr.po @@ -0,0 +1,74 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_revision +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-08-07 13:26+0000\n" +"Last-Translator: Ömer KÜLAK \n" +"Language-Team: none\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__active +msgid "Active" +msgstr "Etkin" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__current_revision_id +msgid "Current revision" +msgstr "Güncel versiyon" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +msgid "Document Revision (abstract)" +msgstr "Doküman Revizyonu" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__has_old_revisions +msgid "Has Old Revisions" +msgstr "Eski Revizyonları Var" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New Revisions" +msgstr "Yeni Revizyonlar" + +#. module: base_revision +#. odoo-python +#: code:addons/base_revision/models/base_revision.py:0 +msgid "New revision created: %s" +msgstr "Yeni revizyon oluşturuldu: %s" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__old_revision_ids +msgid "Old revisions" +msgstr "Eski Revizeler" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__unrevisioned_name +msgid "Original Reference" +msgstr "Orjinal Referans" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_count +msgid "Previous versions count" +msgstr "Önceki versiyon sayısı" + +#. module: base_revision +#: model:ir.model.constraint,message:base_revision.constraint_base_revision_revision_unique +msgid "Reference and revision must be unique." +msgstr "Referans ve revizyon benzersiz olmalıdır." + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision__revision_number +msgid "Revision" +msgstr "Revize" diff --git a/base_revision/models/__init__.py b/base_revision/models/__init__.py new file mode 100644 index 0000000000..87cc68f98e --- /dev/null +++ b/base_revision/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import base_revision diff --git a/base_revision/models/base_revision.py b/base_revision/models/base_revision.py new file mode 100644 index 0000000000..9e33402d84 --- /dev/null +++ b/base_revision/models/base_revision.py @@ -0,0 +1,133 @@ +# Copyright 2013 Agile Business Group sagl () +# Copyright 2016 Serpent Consulting Services Pvt. Ltd. +# Copyright 2018 Dreambits Technologies Pvt. Ltd. () +# Copyright 2020 Ecosoft Co., Ltd. () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models +from odoo.fields import Command + + +class BaseRevision(models.AbstractModel): + _name = "base.revision" + _description = "Document Revision (abstract)" + + @api.depends("old_revision_ids") + def _compute_has_old_revisions(self): + for rec in self: + rec.has_old_revisions = ( + True if rec.with_context(active_test=False).old_revision_ids else False + ) + + current_revision_id = fields.Many2one( + comodel_name="base.revision", + string="Current revision", + readonly=True, + copy=True, + ) + old_revision_ids = fields.One2many( + comodel_name="base.revision", + inverse_name="current_revision_id", + string="Old revisions", + readonly=True, + domain=["|", ("active", "=", False), ("active", "=", True)], + context={"active_test": False}, + ) + revision_number = fields.Integer(string="Revision", copy=False, default=0) + unrevisioned_name = fields.Char( + string="Original Reference", copy=True, readonly=True + ) + active = fields.Boolean(default=True) + has_old_revisions = fields.Boolean(compute="_compute_has_old_revisions") + revision_count = fields.Integer( + compute="_compute_revision_count", string="Previous versions count" + ) + + @api.depends("old_revision_ids") + def _compute_revision_count(self): + res = ( + self.with_context(active_test=False) + .sudo() + .formatted_read_group( + domain=[("current_revision_id", "in", self.ids)], + groupby=["current_revision_id"], + aggregates=["__count"], + ) + ) + revision_dict = {x["current_revision_id"][0]: x["__count"] for x in res} + for rec in self: + rec.revision_count = revision_dict.get(rec.id, 0) + + _revision_unique = models.Constraint( + "unique(unrevisioned_name, revision_number)", + "Reference and revision must be unique.", + ) + + def copy(self, default=None): + default = default or {} + if "unrevisioned_name" not in default: + default["unrevisioned_name"] = False + revision_records = super().copy(default=default) + for rec in revision_records: + if rec.unrevisioned_name: + continue + name_field = self.env.context.get("revision_name_field", "name") + rec.write({"unrevisioned_name": rec[name_field]}) + return revision_records + + def _get_new_rev_data(self, new_rev_number): + self.ensure_one() + return { + "revision_number": new_rev_number, + "unrevisioned_name": self.unrevisioned_name, + "name": f"{self.unrevisioned_name}-{new_rev_number:02d}", + "old_revision_ids": [Command.link(self.id)], + } + + def _prepare_revision_data(self, new_revision): + return {"active": False, "current_revision_id": new_revision.id} + + def copy_revision_with_context(self): + default_data = self.default_get([]) + new_rev_number = self.revision_number + 1 + vals = self._get_new_rev_data(new_rev_number) + default_data.update(vals) + new_revision = self.copy(default_data) + self.old_revision_ids.write({"current_revision_id": new_revision.id}) + self.write(self._prepare_revision_data(new_revision)) + return new_revision + + @api.model_create_multi + def create(self, vals_list): + name_field = self.env.context.get("revision_name_field", "name") + for vals in vals_list: + if "unrevisioned_name" not in vals: + vals["unrevisioned_name"] = vals[name_field] + + return super().create(vals_list) + + def create_revision(self): + revision_ids = [] + # Looping over records + for rec in self: + # Calling Copy method + copied_rec = rec.copy_revision_with_context() + if hasattr(self, "message_post"): + target_msg = self.env._( + "New revision created from: %s", rec._get_html_link() + ) + copied_rec.message_post(body=target_msg) + source_msg = self.env._( + "New revision created: %s", copied_rec._get_html_link() + ) + rec.message_post(body=source_msg) + revision_ids.append(copied_rec.id) + action = { + "type": "ir.actions.act_window", + "view_mode": "list,form", + "name": self.env._("New Revisions"), + "res_model": self._name, + "domain": f"[('id', 'in', {revision_ids})]", + "target": "current", + } + return action diff --git a/base_revision/pyproject.toml b/base_revision/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/base_revision/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/base_revision/readme/CONTRIBUTORS.md b/base_revision/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..ccf504d657 --- /dev/null +++ b/base_revision/readme/CONTRIBUTORS.md @@ -0,0 +1,9 @@ +- Devang Pipaliya \<\> +- Lorenzo Battistini \<\> +- Raphael Valyi \<\> +- Alexandre Fayolle \<\> +- Serpent Consulting Services Pvt. Ltd. \<\> +- Akim Juillerat \<\> +- Raf Ven \<\> +- Jeroen Evens \<\> +- Kitti U. \<\> diff --git a/base_revision/readme/DESCRIPTION.md b/base_revision/readme/DESCRIPTION.md new file mode 100644 index 0000000000..4c46f97448 --- /dev/null +++ b/base_revision/readme/DESCRIPTION.md @@ -0,0 +1,31 @@ +Making revision(s) of a document is a common need across many area. + +This module does not provide a functionality by itself but an abstract +model to implement revision capality in other models (e.g. purchase +orders, sales orders, budgets, expenses...). + +**Note:** To be able to use this module in a new model you will need +some development. + +See [sale_order_revision](https://github.com/OCA/sale-workflow) as an +example of implementation. + +Example with sale_order_revision installed, + +On a cancelled orders, you can click on the "New copy of Quotation" +button. This will create a new revision of the quotation, with the same +base number and a '-revno' suffix appended. A message is added in the +chatter saying that a new revision was created. + +In the form view, a new tab is added that lists the previous revisions, +with the date they were made obsolete and the user who performed the +action. + +The old revisions of a sale order are flagged as inactive, so they don't +clutter up searches. + +**Special Remarks:** Starting on version 14, this module was splitted +from sale_order_revision to, + +- base_revision +- sale_order_revision diff --git a/base_revision/static/description/icon.png b/base_revision/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/base_revision/static/description/icon.png differ diff --git a/base_revision/static/description/index.html b/base_revision/static/description/index.html new file mode 100644 index 0000000000..14529c8370 --- /dev/null +++ b/base_revision/static/description/index.html @@ -0,0 +1,465 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Base Revision (abstract)

+ +

Beta License: AGPL-3 OCA/server-ux Translate me on Weblate Try me on Runboat

+

Making revision(s) of a document is a common need across many area.

+

This module does not provide a functionality by itself but an abstract +model to implement revision capality in other models (e.g. purchase +orders, sales orders, budgets, expenses…).

+

Note: To be able to use this module in a new model you will need +some development.

+

See sale_order_revision as an +example of implementation.

+

Example with sale_order_revision installed,

+

On a cancelled orders, you can click on the “New copy of Quotation” +button. This will create a new revision of the quotation, with the same +base number and a ‘-revno’ suffix appended. A message is added in the +chatter saying that a new revision was created.

+

In the form view, a new tab is added that lists the previous revisions, +with the date they were made obsolete and the user who performed the +action.

+

The old revisions of a sale order are flagged as inactive, so they don’t +clutter up searches.

+

Special Remarks: Starting on version 14, this module was splitted +from sale_order_revision to,

+
    +
  • base_revision
  • +
  • sale_order_revision
  • +
+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Agile Business Group
  • +
  • Dreambits
  • +
  • Camptocamp
  • +
  • Akretion
  • +
  • Serpent Consulting Services Pvt. Ltd.
  • +
  • Ecosoft
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-ux project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/base_revision/tests/__init__.py b/base_revision/tests/__init__.py new file mode 100644 index 0000000000..301c78bad3 --- /dev/null +++ b/base_revision/tests/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import test_base_revision diff --git a/base_revision/tests/base_revision_tester.py b/base_revision/tests/base_revision_tester.py new file mode 100644 index 0000000000..7a46f6cd06 --- /dev/null +++ b/base_revision/tests/base_revision_tester.py @@ -0,0 +1,32 @@ +# Copyright 2020 Ecosoft (http://ecosoft.co.th) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class BaseRevisionTester(models.Model): + _name = "base.revision.tester" + _description = "Base Revision Tester" + _inherit = ["base.revision"] + + name = fields.Char(required=True) + state = fields.Selection( + selection=[ + ("draft", "Draft"), + ("confirmed", "Confirmed"), + ("cancel", "Cancel"), + ], + default="draft", + ) + current_revision_id = fields.Many2one( + comodel_name="base.revision.tester", + ) + old_revision_ids = fields.One2many( + comodel_name="base.revision.tester", + ) + + def action_confirm(self): + self.write({"state": "confirmed"}) + + def action_cancel(self): + self.write({"state": "cancel"}) diff --git a/base_revision/tests/test_base_revision.py b/base_revision/tests/test_base_revision.py new file mode 100644 index 0000000000..5dfb003155 --- /dev/null +++ b/base_revision/tests/test_base_revision.py @@ -0,0 +1,98 @@ +# Copyright 2013 Agile Business Group sagl () +# Copyright 2016 Serpent Consulting Services Pvt. Ltd. +# Copyright 2018 Dreambits Technologies Pvt. Ltd. () +# Copyright 2020 Ecosoft () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo.orm.model_classes import add_to_registry +from odoo.tests import common + + +class TestBaseRevision(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + from .base_revision_tester import BaseRevisionTester + + add_to_registry(cls.registry, BaseRevisionTester) + cls.registry._setup_models__(cls.env.cr, ["base.revision.tester"]) + cls.registry.init_models( + cls.env.cr, ["base.revision.tester"], {"models_to_check": True} + ) + cls.addClassCleanup(cls.registry.__delitem__, "base.revision.tester") + cls.revision_model = cls.env[BaseRevisionTester._name] + + def _create_tester(self, vals_list=None): + if not vals_list: + vals_list = [{}] + for vals in vals_list: + if "name" not in vals: + vals["name"] = "TEST0001" + return self.revision_model.create(vals_list) + + @staticmethod + def _revision_tester(tester): + # Cancel the tester + tester.action_cancel() + # Create a new revision + return tester.create_revision() + + def test_revision(self): + """Check revision process""" + # Create a Tester document + tester_1 = self._create_tester() + + # Create a revision of the Tester + self._revision_tester(tester_1) + + # Check the previous revision of the tester + revision_1 = tester_1.current_revision_id + self.assertEqual(tester_1.state, "cancel") + + # Check the current revision of the tester + self.assertEqual(revision_1.unrevisioned_name, tester_1.name) + self.assertEqual(revision_1.state, "draft") + self.assertTrue(revision_1.active) + self.assertEqual(revision_1.old_revision_ids, tester_1) + self.assertEqual(revision_1.revision_number, 1) + self.assertEqual(revision_1.name.endswith("-01"), True) + self.assertEqual(revision_1.has_old_revisions, True) + self.assertEqual(revision_1.revision_count, 1) + + # Create a new revision of the tester + self._revision_tester(revision_1) + revision_2 = revision_1.current_revision_id + + # Check the previous revision of the tester + self.assertEqual(revision_1.state, "cancel") + self.assertFalse(revision_1.active) + + # Check the current revision of the tester + self.assertEqual(revision_2.unrevisioned_name, tester_1.name) + self.assertEqual(revision_2, tester_1.current_revision_id) + self.assertEqual(revision_2.state, "draft") + self.assertTrue(revision_2.active) + self.assertEqual(revision_2.old_revision_ids, tester_1 + revision_1) + self.assertEqual(revision_2.revision_number, 2) + self.assertEqual(revision_2.name.endswith("-02"), True) + self.assertEqual(revision_2.has_old_revisions, True) + self.assertEqual(revision_2.revision_count, 2) + + def test_simple_copy(self): + """Check copy process""" + # Create a tester + tester_2 = self._create_tester() + # Check the 'Order Reference' of the tester + self.assertEqual(tester_2.name, tester_2.unrevisioned_name) + + # Copy the tester + tester_3 = tester_2.copy({"name": "TEST0002"}) + # Check the 'Reference' of the copied tester + self.assertEqual(tester_3.name, tester_3.unrevisioned_name) + + def test_create_multiple(self): + """Check copy process""" + # Create a tester + tester_2 = self._create_tester([{"name": "TEST0001"}, {"name": "TEST0002"}]) + # Check the 'Order Reference' of the tester + for tester in tester_2: + self.assertEqual(tester.name, tester.unrevisioned_name) diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index e80ef079b1..19be08ca9c 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,8 +1,9 @@ [project] name = "odoo-addons-oca-server-ux" -version = "19.0.20260319.0" +version = "19.0.20260416.0" dependencies = [ "odoo-addon-base_cancel_confirm==19.0.*", + "odoo-addon-base_revision==19.0.*", "odoo-addon-base_search_custom_field_filter==19.0.*", "odoo-addon-base_substate==19.0.*", "odoo-addon-base_technical_features==19.0.*",