From 1664971c9666366a4e11f6cdc2158353e2b6ac7c Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 1 Mar 2021 16:09:08 +0000 Subject: [PATCH 001/161] [14.0][ADD] base_revision --- base_revision/README.rst | 113 +++++ base_revision/__init__.py | 2 + base_revision/__manifest__.py | 23 + base_revision/i18n/base_revision.pot | 81 ++++ base_revision/models/__init__.py | 3 + base_revision/models/base_revision.py | 111 +++++ base_revision/readme/CONTRIBUTORS.rst | 9 + base_revision/readme/DESCRIPTION.rst | 28 ++ base_revision/static/description/icon.png | Bin 0 -> 9455 bytes base_revision/static/description/index.html | 452 ++++++++++++++++++++ base_revision/tests/__init__.py | 4 + base_revision/tests/base_revision_tester.py | 32 ++ base_revision/tests/test_base_revision.py | 88 ++++ 13 files changed, 946 insertions(+) create mode 100644 base_revision/README.rst create mode 100644 base_revision/__init__.py create mode 100644 base_revision/__manifest__.py create mode 100644 base_revision/i18n/base_revision.pot create mode 100644 base_revision/models/__init__.py create mode 100644 base_revision/models/base_revision.py create mode 100644 base_revision/readme/CONTRIBUTORS.rst create mode 100644 base_revision/readme/DESCRIPTION.rst create mode 100644 base_revision/static/description/icon.png create mode 100644 base_revision/static/description/index.html create mode 100644 base_revision/tests/__init__.py create mode 100644 base_revision/tests/base_revision_tester.py create mode 100644 base_revision/tests/test_base_revision.py diff --git a/base_revision/README.rst b/base_revision/README.rst new file mode 100644 index 0000000000..4d30690cc6 --- /dev/null +++ b/base_revision/README.rst @@ -0,0 +1,113 @@ +======================== +Base Revision (abstract) +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-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/14.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-14-0/server-ux-14-0-base_revision + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/250/14.0 + :alt: Try me on Runbot + +|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 smashing 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..47885f0472 --- /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": "14.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..0cb1c334c1 --- /dev/null +++ b/base_revision/i18n/base_revision.pot @@ -0,0 +1,81 @@ +# 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" +"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 +#: model:ir.model.fields,field_description:base_revision.field_base_revision____last_update +msgid "Last Modified on" +msgstr "" + +#. module: base_revision +#: code:addons/base_revision/models/base_revision.py:0 +#, python-format +msgid "New Revisions" +msgstr "" + +#. module: base_revision +#: code:addons/base_revision/models/base_revision.py:0 +#, python-format +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.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/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..1422035130 --- /dev/null +++ b/base_revision/models/base_revision.py @@ -0,0 +1,111 @@ +# 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 + + +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") + + _sql_constraints = [ + ( + "revision_unique", + "unique(unrevisioned_name, revision_number)", + "Reference and revision must be unique.", + ) + ] + + @api.returns("self", lambda value: value.id) + def copy(self, default=None): + default = default or {} + if "unrevisioned_name" not in default: + default["unrevisioned_name"] = False + rec = super().copy(default=default) + if not rec.unrevisioned_name: + name_field = self._context.get("revision_name_field", "name") + rec.write({"unrevisioned_name": rec[name_field]}) + return rec + + def _get_new_rev_data(self, new_rev_number): + self.ensure_one() + return { + "revision_number": new_rev_number, + "unrevisioned_name": self.unrevisioned_name, + "name": "%s-%02d" % (self.unrevisioned_name, new_rev_number), + "old_revision_ids": [(4, self.id, False)], + } + + 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( + {"active": False, "state": "cancel", "current_revision_id": new_revision.id} + ) + return new_revision + + @api.model + def create(self, values): + rec = super().create(values) + if "unrevisioned_name" not in values: + name_field = self._context.get("revision_name_field", "name") + rec.write({"unrevisioned_name": rec[name_field]}) + return rec + + 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"): + msg = _("New revision created: %s") % copied_rec.name + copied_rec.message_post(body=msg) + rec.message_post(body=msg) + revision_ids.append(copied_rec.id) + action = { + "type": "ir.actions.act_window", + "view_mode": "tree,form", + "name": _("New Revisions"), + "res_model": self._name, + "domain": "[('id', 'in', %s)]" % revision_ids, + "auto_search": True, + "target": "current", + "nodestroy": True, + } + return action diff --git a/base_revision/readme/CONTRIBUTORS.rst b/base_revision/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..8192f62d71 --- /dev/null +++ b/base_revision/readme/CONTRIBUTORS.rst @@ -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.rst b/base_revision/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..5f6db8f94a --- /dev/null +++ b/base_revision/readme/DESCRIPTION.rst @@ -0,0 +1,28 @@ +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 diff --git a/base_revision/static/description/icon.png b/base_revision/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/base_revision/static/description/index.html b/base_revision/static/description/index.html new file mode 100644 index 0000000000..d46fc1bd7e --- /dev/null +++ b/base_revision/static/description/index.html @@ -0,0 +1,452 @@ + + + + + + +Base Revision (abstract) + + + +
+

Base Revision (abstract)

+ + +

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

+

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 smashing 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..5fb530e259 --- /dev/null +++ b/base_revision/tests/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import test_base_revision + +# from . import common 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..f416f4aba8 --- /dev/null +++ b/base_revision/tests/test_base_revision.py @@ -0,0 +1,88 @@ +# 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_test_helper import FakeModelLoader + +from odoo.tests import common + + +class TestBaseRevision(common.SavepointCase): + @classmethod + def setUpClass(cls): + super(TestBaseRevision, cls).setUpClass() + + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from .base_revision_tester import BaseRevisionTester + + cls.loader.update_registry((BaseRevisionTester,)) + + cls.revision_model = cls.env[BaseRevisionTester._name] + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super(TestBaseRevision, cls).tearDownClass() + + def _create_tester(self): + return self.revision_model.create({"name": "TEST0001"}) + + @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) + + # 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) + + 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) From 71b8fd0d6f6a608cb5a55f03c5158a20cfdb3014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Su=C3=A1rez?= Date: Tue, 16 Mar 2021 09:34:47 +0000 Subject: [PATCH 002/161] Translated using Weblate (Spanish) Currently translated at 92.3% (12 of 13 strings) Translation: server-ux-14.0/server-ux-14.0-base_revision Translate-URL: https://translation.odoo-community.org/projects/server-ux-14-0/server-ux-14-0-base_revision/es/ Added translation using Weblate (Spanish) --- base_revision/i18n/es.po | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 base_revision/i18n/es.po diff --git a/base_revision/i18n/es.po b/base_revision/i18n/es.po new file mode 100644 index 0000000000..46fc5d2f4e --- /dev/null +++ b/base_revision/i18n/es.po @@ -0,0 +1,85 @@ +# 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" +"PO-Revision-Date: 2021-03-16 11:46+0000\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: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\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.fields,field_description:base_revision.field_base_revision__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: base_revision +#: model:ir.model,name:base_revision.model_base_revision +#, fuzzy +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 +#: model:ir.model.fields,field_description:base_revision.field_base_revision__id +msgid "ID" +msgstr "ID" + +#. module: base_revision +#: model:ir.model.fields,field_description:base_revision.field_base_revision____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: base_revision +#: code:addons/base_revision/models/base_revision.py:0 +#, python-format +msgid "New Revisions" +msgstr "Nuevas revisiones" + +#. module: base_revision +#: code:addons/base_revision/models/base_revision.py:0 +#, python-format +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.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" From 223ee461a1897c4518e25f706d7776696022a9d4 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 20 May 2021 14:27:23 +0000 Subject: [PATCH 003/161] [FIX] base_revision: auto_search and no_destroy are no longer valid attributes base_revision 14.0.1.0.1 --- base_revision/__manifest__.py | 2 +- base_revision/models/base_revision.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/base_revision/__manifest__.py b/base_revision/__manifest__.py index 47885f0472..9f0bca5d2c 100644 --- a/base_revision/__manifest__.py +++ b/base_revision/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Base Revision (abstract)", "summary": "Keep track of revised document", - "version": "14.0.1.0.0", + "version": "14.0.1.0.1", "category": "Tools", "author": "Agile Business Group," "Dreambits," diff --git a/base_revision/models/base_revision.py b/base_revision/models/base_revision.py index 1422035130..bcac5ad2fa 100644 --- a/base_revision/models/base_revision.py +++ b/base_revision/models/base_revision.py @@ -104,8 +104,6 @@ def create_revision(self): "name": _("New Revisions"), "res_model": self._name, "domain": "[('id', 'in', %s)]" % revision_ids, - "auto_search": True, "target": "current", - "nodestroy": True, } return action From 14fb7ff82da31ebe5ca3b3b785d465ffdde5e88f Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 23 Feb 2022 14:49:06 +0000 Subject: [PATCH 004/161] [IMP] base_revision: Add revisions_count field + update the state field if it exists in the model. [UPD] Update base_revision.pot base_revision 14.0.1.1.0 --- base_revision/__manifest__.py | 2 +- base_revision/i18n/base_revision.pot | 5 +++++ base_revision/i18n/es.po | 13 +++++++++---- base_revision/models/base_revision.py | 23 ++++++++++++++++++++--- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/base_revision/__manifest__.py b/base_revision/__manifest__.py index 9f0bca5d2c..fa0fc7c744 100644 --- a/base_revision/__manifest__.py +++ b/base_revision/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Base Revision (abstract)", "summary": "Keep track of revised document", - "version": "14.0.1.0.1", + "version": "14.0.1.1.0", "category": "Tools", "author": "Agile Business Group," "Dreambits," diff --git a/base_revision/i18n/base_revision.pot b/base_revision/i18n/base_revision.pot index 0cb1c334c1..577b15d239 100644 --- a/base_revision/i18n/base_revision.pot +++ b/base_revision/i18n/base_revision.pot @@ -70,6 +70,11 @@ msgstr "" 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." diff --git a/base_revision/i18n/es.po b/base_revision/i18n/es.po index 46fc5d2f4e..af9b642db4 100644 --- a/base_revision/i18n/es.po +++ b/base_revision/i18n/es.po @@ -6,15 +6,16 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2021-03-16 11:46+0000\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: \n" +"Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3.2\n" +"X-Generator: Poedit 2.3\n" #. module: base_revision #: model:ir.model.fields,field_description:base_revision.field_base_revision__active @@ -33,7 +34,6 @@ msgstr "Nombre mostrado" #. module: base_revision #: model:ir.model,name:base_revision.model_base_revision -#, fuzzy msgid "Document Revision (abstract)" msgstr "Revisión Documento (resumen)" @@ -74,6 +74,11 @@ msgstr "Revisiones antiguas" 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." diff --git a/base_revision/models/base_revision.py b/base_revision/models/base_revision.py index bcac5ad2fa..4007b05144 100644 --- a/base_revision/models/base_revision.py +++ b/base_revision/models/base_revision.py @@ -38,6 +38,22 @@ def _compute_has_old_revisions(self): ) 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).read_group( + domain=[("current_revision_id", "in", self.ids)], + fields=["current_revision_id"], + groupby=["current_revision_id"], + ) + revision_dict = { + x["current_revision_id"][0]: x["current_revision_id_count"] for x in res + } + for rec in self: + rec.revision_count = revision_dict.get(rec.id, 0) _sql_constraints = [ ( @@ -67,6 +83,9 @@ def _get_new_rev_data(self, new_rev_number): "old_revision_ids": [(4, self.id, False)], } + 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 @@ -74,9 +93,7 @@ def copy_revision_with_context(self): default_data.update(vals) new_revision = self.copy(default_data) self.old_revision_ids.write({"current_revision_id": new_revision.id}) - self.write( - {"active": False, "state": "cancel", "current_revision_id": new_revision.id} - ) + self.write(self._prepare_revision_data(new_revision)) return new_revision @api.model From 55f2e64e992887a6e818218f1b09b1b3666eecb7 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 20 Sep 2022 17:09:23 +0000 Subject: [PATCH 005/161] [MIG] base_revision: Migration to 15.0 [UPD] Update base_revision.pot [UPD] README.rst --- base_revision/README.rst | 10 +++++----- base_revision/__manifest__.py | 2 +- base_revision/i18n/base_revision.pot | 17 +---------------- base_revision/static/description/index.html | 6 +++--- base_revision/tests/test_base_revision.py | 6 ++++-- 5 files changed, 14 insertions(+), 27 deletions(-) diff --git a/base_revision/README.rst b/base_revision/README.rst index 4d30690cc6..6d919c9890 100644 --- a/base_revision/README.rst +++ b/base_revision/README.rst @@ -14,13 +14,13 @@ Base Revision (abstract) :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/14.0/base_revision + :target: https://github.com/OCA/server-ux/tree/15.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-14-0/server-ux-14-0-base_revision + :target: https://translation.odoo-community.org/projects/server-ux-15-0/server-ux-15-0-base_revision :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/250/14.0 + :target: https://runbot.odoo-community.org/runbot/250/15.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -65,7 +65,7 @@ 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 smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -108,6 +108,6 @@ 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. +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/__manifest__.py b/base_revision/__manifest__.py index fa0fc7c744..6769a2306a 100644 --- a/base_revision/__manifest__.py +++ b/base_revision/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Base Revision (abstract)", "summary": "Keep track of revised document", - "version": "14.0.1.1.0", + "version": "15.0.1.0.0", "category": "Tools", "author": "Agile Business Group," "Dreambits," diff --git a/base_revision/i18n/base_revision.pot b/base_revision/i18n/base_revision.pot index 577b15d239..5a990e6805 100644 --- a/base_revision/i18n/base_revision.pot +++ b/base_revision/i18n/base_revision.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -23,11 +23,6 @@ msgstr "" 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)" @@ -38,16 +33,6 @@ msgstr "" 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 -#: model:ir.model.fields,field_description:base_revision.field_base_revision____last_update -msgid "Last Modified on" -msgstr "" - #. module: base_revision #: code:addons/base_revision/models/base_revision.py:0 #, python-format diff --git a/base_revision/static/description/index.html b/base_revision/static/description/index.html index d46fc1bd7e..553964a301 100644 --- a/base_revision/static/description/index.html +++ b/base_revision/static/description/index.html @@ -367,7 +367,7 @@

Base Revision (abstract)

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

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 @@ -406,7 +406,7 @@

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 smashing it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -443,7 +443,7 @@

Maintainers

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.

+

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/test_base_revision.py b/base_revision/tests/test_base_revision.py index f416f4aba8..8e1557c5e2 100644 --- a/base_revision/tests/test_base_revision.py +++ b/base_revision/tests/test_base_revision.py @@ -8,7 +8,7 @@ from odoo.tests import common -class TestBaseRevision(common.SavepointCase): +class TestBaseRevision(common.TransactionCase): @classmethod def setUpClass(cls): super(TestBaseRevision, cls).setUpClass() @@ -24,7 +24,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.loader.restore_registry() - super(TestBaseRevision, cls).tearDownClass() + return super(TestBaseRevision, cls).tearDownClass() def _create_tester(self): return self.revision_model.create({"name": "TEST0001"}) @@ -56,6 +56,7 @@ def test_revision(self): 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) @@ -74,6 +75,7 @@ def test_revision(self): 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""" From 59580e7bc59b8021d3bca85aaf2c3a73ca52005d Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 13 Mar 2023 12:11:33 +0000 Subject: [PATCH 006/161] [MIG] base_revision: Migration to 16.0 [UPD] Update base_revision.pot [UPD] README.rst Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: server-ux-16.0/server-ux-16.0-base_revision Translate-URL: https://translation.odoo-community.org/projects/server-ux-16-0/server-ux-16-0-base_revision/ --- base_revision/README.rst | 10 ++++---- base_revision/__manifest__.py | 2 +- base_revision/i18n/base_revision.pot | 4 +++- base_revision/i18n/es.po | 26 +++++++++------------ base_revision/static/description/index.html | 6 ++--- 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/base_revision/README.rst b/base_revision/README.rst index 6d919c9890..dfedb2197a 100644 --- a/base_revision/README.rst +++ b/base_revision/README.rst @@ -14,13 +14,13 @@ Base Revision (abstract) :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/15.0/base_revision + :target: https://github.com/OCA/server-ux/tree/16.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-15-0/server-ux-15-0-base_revision + :target: https://translation.odoo-community.org/projects/server-ux-16-0/server-ux-16-0-base_revision :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/250/15.0 + :target: https://runbot.odoo-community.org/runbot/250/16.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -65,7 +65,7 @@ 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 smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -108,6 +108,6 @@ 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. +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/__manifest__.py b/base_revision/__manifest__.py index 6769a2306a..c465e9bd1e 100644 --- a/base_revision/__manifest__.py +++ b/base_revision/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Base Revision (abstract)", "summary": "Keep track of revised document", - "version": "15.0.1.0.0", + "version": "16.0.1.0.0", "category": "Tools", "author": "Agile Business Group," "Dreambits," diff --git a/base_revision/i18n/base_revision.pot b/base_revision/i18n/base_revision.pot index 5a990e6805..2307f302a9 100644 --- a/base_revision/i18n/base_revision.pot +++ b/base_revision/i18n/base_revision.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 15.0\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -34,12 +34,14 @@ msgid "Has Old Revisions" msgstr "" #. module: base_revision +#. odoo-python #: code:addons/base_revision/models/base_revision.py:0 #, python-format msgid "New Revisions" msgstr "" #. module: base_revision +#. odoo-python #: code:addons/base_revision/models/base_revision.py:0 #, python-format msgid "New revision created: %s" diff --git a/base_revision/i18n/es.po b/base_revision/i18n/es.po index af9b642db4..bf104bbedf 100644 --- a/base_revision/i18n/es.po +++ b/base_revision/i18n/es.po @@ -27,11 +27,6 @@ msgstr "Activo" msgid "Current revision" msgstr "Revisión actual" -#. module: base_revision -#: model:ir.model.fields,field_description:base_revision.field_base_revision__display_name -msgid "Display Name" -msgstr "Nombre mostrado" - #. module: base_revision #: model:ir.model,name:base_revision.model_base_revision msgid "Document Revision (abstract)" @@ -43,22 +38,14 @@ msgid "Has Old Revisions" msgstr "Tiene revisiones antiguas" #. module: base_revision -#: model:ir.model.fields,field_description:base_revision.field_base_revision__id -msgid "ID" -msgstr "ID" - -#. module: base_revision -#: model:ir.model.fields,field_description:base_revision.field_base_revision____last_update -msgid "Last Modified on" -msgstr "Última modificación el" - -#. module: base_revision +#. odoo-python #: code:addons/base_revision/models/base_revision.py:0 #, python-format msgid "New Revisions" msgstr "Nuevas revisiones" #. module: base_revision +#. odoo-python #: code:addons/base_revision/models/base_revision.py:0 #, python-format msgid "New revision created: %s" @@ -88,3 +75,12 @@ msgstr "Referencia y revisión deben ser únicas." #: 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/static/description/index.html b/base_revision/static/description/index.html index 553964a301..7b00119761 100644 --- a/base_revision/static/description/index.html +++ b/base_revision/static/description/index.html @@ -367,7 +367,7 @@

Base Revision (abstract)

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

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 @@ -406,7 +406,7 @@

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 smashing it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -443,7 +443,7 @@

Maintainers

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.

+

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.

From 91c9aa064ba39a1c7c0a70c20c05da93a8a48554 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sun, 3 Sep 2023 16:55:27 +0000 Subject: [PATCH 007/161] [FIX] warning create method in batch base_revision 16.0.1.0.1 [fix] unit test in sale_order_revision fails base_revision 16.0.1.0.2 [UPD] README.rst --- base_revision/README.rst | 15 +++++---- base_revision/__manifest__.py | 2 +- base_revision/models/base_revision.py | 15 ++++----- base_revision/static/description/index.html | 34 +++++++++++---------- base_revision/tests/test_base_revision.py | 17 +++++++++-- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/base_revision/README.rst b/base_revision/README.rst index dfedb2197a..4bcdf7304b 100644 --- a/base_revision/README.rst +++ b/base_revision/README.rst @@ -2,10 +2,13 @@ Base Revision (abstract) ======================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3db67a7a0060d60c004bb472e44d95b2e690b0586185f43dae608ea424575198 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Base Revision (abstract) .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/server-ux-16-0/server-ux-16-0-base_revision :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/250/16.0 - :alt: Try me on Runbot +.. |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=16.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| Making revision(s) of a document is a common need across many area. @@ -64,7 +67,7 @@ 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 smashing it by providing a detailed and welcomed +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. diff --git a/base_revision/__manifest__.py b/base_revision/__manifest__.py index c465e9bd1e..2f88c1e1ff 100644 --- a/base_revision/__manifest__.py +++ b/base_revision/__manifest__.py @@ -7,7 +7,7 @@ { "name": "Base Revision (abstract)", "summary": "Keep track of revised document", - "version": "16.0.1.0.0", + "version": "16.0.1.0.2", "category": "Tools", "author": "Agile Business Group," "Dreambits," diff --git a/base_revision/models/base_revision.py b/base_revision/models/base_revision.py index 4007b05144..3f8cc5d107 100644 --- a/base_revision/models/base_revision.py +++ b/base_revision/models/base_revision.py @@ -96,13 +96,14 @@ def copy_revision_with_context(self): self.write(self._prepare_revision_data(new_revision)) return new_revision - @api.model - def create(self, values): - rec = super().create(values) - if "unrevisioned_name" not in values: - name_field = self._context.get("revision_name_field", "name") - rec.write({"unrevisioned_name": rec[name_field]}) - return rec + @api.model_create_multi + def create(self, vals_list): + name_field = self._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 = [] diff --git a/base_revision/static/description/index.html b/base_revision/static/description/index.html index 7b00119761..034712940a 100644 --- a/base_revision/static/description/index.html +++ b/base_revision/static/description/index.html @@ -1,20 +1,20 @@ - + - + Base Revision (abstract) + + +
+

Base Sub State

+ + +

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

+

This module provide abstract models to manage customizable +substates to be applied on different models (sale order, purchase, …).

+
+

example:

+
    +
  • for the quotation state of a sale order we can define 3 substates “In negotiation”, +“Won” and “Lost”.
  • +
  • We can also send mail when the susbstate is reached.
  • +
+

It is not useful for itself. You can see an example of implementation +in the ‘sale_substate’ module. (sale-workflow repository).

+

Table of contents

+ +
+

Usage

+
    +
  1. You must install an application module depending this one (for example sale_substate)
  2. +
+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

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_substate/tests/__init__.py b/base_substate/tests/__init__.py new file mode 100644 index 0000000000..bc0f1b9e60 --- /dev/null +++ b/base_substate/tests/__init__.py @@ -0,0 +1,4 @@ + +from . import models_mixin +from . import sale_test +from . import test_base_substate diff --git a/base_substate/tests/models_mixin.py b/base_substate/tests/models_mixin.py new file mode 100644 index 0000000000..80d4fb8391 --- /dev/null +++ b/base_substate/tests/models_mixin.py @@ -0,0 +1,128 @@ +# Copyright 2018 Simone Orsi - Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from operator import attrgetter + + +class TestMixin(object): + """Mixin to setup fake models for tests. + + Usage - the model: + + class FakeModel(models.Model, TestMixin): + _name = 'fake.model' + + name = fields.Char() + + Usage - the test klass: + + @classmethod + def setUpClass(cls): + super().setUpClass() + FakeModel._test_setup_model(cls.env) + + @classmethod + def tearDownClass(cls): + FakeModel._test_teardown_model(cls.env) + super().tearDownClass() + """ + + # Generate xmlids + # This is needed if you want to load data tied to a test model via xid. + _test_setup_gen_xid = False + # If you extend a real model (ie: res.partner) you must enable this + # to not delete the model on tear down. + _test_teardown_no_delete = False + # You can add custom fields to real models (eg: res.partner). + # In this case you must delete them to leave registry and model clean. + # This is mandatory for relational fields that link a fake model. + _test_purge_fields = [] + + @classmethod + def _test_setup_models(cls, env, model_clses): + """ + Setup models at the same time + if one fake model ref to another in relational + field. + ex : many2one fields + in this case we should don't use manual=True as an option in field. + """ + for model_cls in model_clses: + model_cls._build_model(env.registry, env.cr) + + env.registry.setup_models(env.cr) + ctx = dict(env.context, update_custom_fields=True) + if cls._test_setup_gen_xid: + ctx["module"] = cls._module + env.registry.init_models( + env.cr, [model_cls._name for model_cls in model_clses], ctx + ) + + @classmethod + def _test_setup_model(cls, env): + """Initialize it.""" + cls._build_model(env.registry, env.cr) + env.registry.setup_models(env.cr) + ctx = dict(env.context, update_custom_fields=True) + if cls._test_setup_gen_xid: + ctx["module"] = cls._module + env.registry.init_models(env.cr, [cls._name], ctx) + + @classmethod + def _test_teardown_model(cls, env): + """Cleanup registry and real models.""" + + for fname in cls._test_purge_fields: + model = env[cls._name] + if fname in model: + model._pop_field(fname) + + if not getattr(cls, "_test_teardown_no_delete", False): + del env.registry.models[cls._name] + # here we must remove the model from list of children of inherited + # models + parents = cls._inherit + parents = [ + parents] if isinstance(parents, str) else (parents or []) + # keep a copy to be sure to not modify the original _inherit + parents = list(parents) + parents.extend(cls._inherits.keys()) + parents.append("base") + funcs = [ + attrgetter(kind + "_children") for kind in + ["_inherits", "_inherit"] + ] + for parent in parents: + for func in funcs: + children = func(env.registry[parent]) + if cls._name in children: + # at this stage our cls is referenced as children of + # parent -> must un reference it + children.remove(cls._name) + + def _test_get_model_id(self): + self.env.cr.execute( + "SELECT id FROM ir_model WHERE model = %s", (self._name,)) + res = self.env.cr.fetchone() + return res[0] if res else None + + def _test_create_ACL(self, **kw): + model_id = self._test_get_model_id() + if not model_id: + self._reflect() + model_id = self._test_get_model_id() + if model_id: + vals = self._test_ACL_values(model_id) + vals.update(kw) + self.env["ir.model.access"].create(vals) + + def _test_ACL_values(self, model_id): + values = { + "name": "Fake ACL for %s" % self._name, + "model_id": model_id, + "perm_read": 1, + "perm_create": 1, + "perm_write": 1, + "perm_unlink": 1, + "active": True, + } + return values diff --git a/base_substate/tests/sale_test.py b/base_substate/tests/sale_test.py new file mode 100644 index 0000000000..618bcf68ed --- /dev/null +++ b/base_substate/tests/sale_test.py @@ -0,0 +1,57 @@ +# Copyright 2020 Akretion Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + +from .models_mixin import TestMixin + + +class SaleTest(models.Model, TestMixin): + _inherit = 'base.substate.mixin' + _name = "base.substate.test.sale" + _description = "Base substate Test Model" + + name = fields.Char(required=True) + user_id = fields.Many2one('res.users', string='Responsible') + state = fields.Selection( + [('draft', 'New'), ('cancel', 'Cancelled'), + ('sale', 'Sale'), + ('done', 'Done')], + string="Status", readonly=True, default='draft') + active = fields.Boolean(default=True) + partner_id = fields.Many2one('res.partner', string='Partner') + line_ids = fields.One2many( + comodel_name='base.substate.test.sale.line', + inverse_name='sale_id', + context={"active_test": False}, + ) + amount_total = fields.Float( + compute='_compute_amount_total', store=True) + + @api.depends('line_ids') + def _compute_amount_total(cls): + for record in cls: + for line in record.line_ids: + record.amount_total += line.amount * line.qty + + @api.multi + def button_confirm(cls): + cls.write({'state': 'sale'}) + return True + + @api.multi + def button_cancel(cls): + cls.write({'state': 'cancel'}) + + +class LineTest(models.Model, TestMixin): + _name = "base.substate.test.sale.line" + _description = "Base substate Test Model Line" + + name = fields.Char() + sale_id = fields.Many2one( + comodel_name='base.substate.test.sale', + ondelete='cascade', + context={"active_test": False}, + ) + qty = fields.Float() + amount = fields.Float() diff --git a/base_substate/tests/test_base_substate.py b/base_substate/tests/test_base_substate.py new file mode 100644 index 0000000000..ec8b07f4b9 --- /dev/null +++ b/base_substate/tests/test_base_substate.py @@ -0,0 +1,104 @@ +# Copyright 2020 Akretion Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests import common +from .sale_test import SaleTest, LineTest + + +@common.at_install(False) +@common.post_install(True) +class TestBaseSubstate(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestBaseSubstate, cls).setUpClass() + SaleTest._test_setup_models(cls.env, [SaleTest, LineTest]) + LineTest._test_setup_model(cls.env) + + cls.substate_test_sale = cls.env['base.substate.test.sale'] + cls.substate_test_sale_line = cls.env['base.substate.test.sale.line'] + + cls.base_substate = cls.env['base.substate.mixin'] + cls.substate_type = cls.env['base.substate.type'] + + cls.substate_type._fields['model'].selection.append( + ('base.substate.test.sale', 'Sale Order')) + + cls.substate_type = cls.env['base.substate.type'].create({ + 'name': "Sale", + 'model': "base.substate.test.sale", + 'target_state_field': "state", + }) + + cls.substate_val_quotation = cls.env['target.state.value'].create({ + 'name': "Quotation", + 'base_substate_type_id': cls.substate_type.id, + 'target_state_value': "draft", + }) + + cls.substate_val_sale = cls.env['target.state.value'].create({ + 'name': "Sale order", + 'base_substate_type_id': cls.substate_type.id, + 'target_state_value': "sale", + }) + cls.substate_under_negotiation = cls.env['base.substate'].create({ + 'name': "Under negotiation", + 'sequence': 1, + 'target_state_value_id': cls.substate_val_quotation.id, + }) + + cls.substate_won = cls.env['base.substate'].create({ + 'name': "Won", + 'sequence': 1, + 'target_state_value_id': cls.substate_val_quotation.id, + }) + + cls.substate_wait_docs = cls.env['base.substate'].create({ + 'name': "Waiting for legal documents", + 'sequence': 2, + 'target_state_value_id': cls.substate_val_sale.id, + }) + + cls.substate_valid_docs = cls.env['base.substate'].create({ + 'name': "To validate legal documents", + 'sequence': 3, + 'target_state_value_id': cls.substate_val_sale.id, + }) + + cls.substate_in_delivering = cls.env['base.substate'].create({ + 'name': "In delivering", + 'sequence': 4, + 'target_state_value_id': cls.substate_val_sale.id, + }) + + @classmethod + def tearDownClass(cls): + SaleTest._test_teardown_model(cls.env) + LineTest._test_teardown_model(cls.env) + super().tearDownClass() + + def test_sale_order_substate(self): + partner = self.env.ref('base.res_partner_1') + so_test1 = self.substate_test_sale.create({ + 'name': 'Test base substate to basic sale', + 'partner_id': partner.id, + 'line_ids': [(0, 0, { + 'name': "line test", + 'amount': 120.0, + 'qty': 1.5, + })], + }) + self.assertTrue(so_test1.state == 'draft') + self.assertTrue(so_test1.substate_id == + self.substate_under_negotiation) + + # Test that validation of sale order change substate_id + so_test1.button_confirm() + self.assertTrue(so_test1.state == 'sale') + self.assertTrue(so_test1.substate_id == self.substate_wait_docs) + + # Test that substate_id is set to false if + # there is not substate corresponding to state + so_test1.button_cancel() + self.assertTrue(so_test1.state == 'cancel') + self.assertTrue(not so_test1.substate_id) diff --git a/base_substate/views/base_substate_type_views.xml b/base_substate/views/base_substate_type_views.xml new file mode 100644 index 0000000000..ef8bfbffa9 --- /dev/null +++ b/base_substate/views/base_substate_type_views.xml @@ -0,0 +1,79 @@ + + + + + base.substate.type + + + + + + + + + + + base.substate.type + +
+ +
+
+ + + + + + +
+
+
+
+ + + base.substate.type + + + + + + + + + + + Sub State Type + ir.actions.act_window + base.substate.type + form + tree,form + + [] + {} + + + + + + form + + + + + + + tree + + + + +
diff --git a/base_substate/views/base_substate_value_views.xml b/base_substate/views/base_substate_value_views.xml new file mode 100644 index 0000000000..be3dad089b --- /dev/null +++ b/base_substate/views/base_substate_value_views.xml @@ -0,0 +1,76 @@ + + + + + target.state.value + + + + + + + + + + + target.state.value + +
+ +
+
+ + + + + + +
+
+
+
+ + + target.state.value + + + + + + + + + + + Target State Value + ir.actions.act_window + target.state.value + form + tree,form + + [] + {} + + + + + + form + + + + + + + tree + + + + +
diff --git a/base_substate/views/base_substate_views.xml b/base_substate/views/base_substate_views.xml new file mode 100644 index 0000000000..f52d10969b --- /dev/null +++ b/base_substate/views/base_substate_views.xml @@ -0,0 +1,84 @@ + + + + + base.substate + + + + + + + + + + + + + base.substate + +
+ +
+ +
+
+
+ + + + + + + + + +
+
+
+
+ + + base.substate + + + + + + + + + Base Substate + ir.actions.act_window + base.substate + form + tree,form + + [] + {} + + + + + + form + + + + + + + tree + + + + +
From a4ddc27a24b96ab6c736d7605e0a29dd7117fa56 Mon Sep 17 00:00:00 2001 From: Kitti U Date: Sun, 30 Aug 2020 10:45:46 +0700 Subject: [PATCH 023/161] [IMP] base_substate: black, isort, prettier --- base_substate/__manifest__.py | 4 +- base_substate/models/base_substate.py | 75 ++++---- base_substate/models/base_substate_mixin.py | 56 +++--- base_substate/readme/USAGE.rst | 2 +- .../security/base_substate_security.xml | 6 +- base_substate/tests/__init__.py | 1 - base_substate/tests/models_mixin.py | 9 +- base_substate/tests/sale_test.py | 32 ++-- base_substate/tests/test_base_substate.py | 160 +++++++++-------- .../views/base_substate_type_views.xml | 155 +++++++++-------- .../views/base_substate_value_views.xml | 150 ++++++++-------- base_substate/views/base_substate_views.xml | 164 +++++++++--------- 12 files changed, 429 insertions(+), 385 deletions(-) diff --git a/base_substate/__manifest__.py b/base_substate/__manifest__.py index 59e08fb2e2..ddc8c4ce96 100644 --- a/base_substate/__manifest__.py +++ b/base_substate/__manifest__.py @@ -10,8 +10,8 @@ "license": "AGPL-3", "depends": ["base"], "data": [ - 'security/base_substate_security.xml', - 'security/ir.model.access.csv', + "security/base_substate_security.xml", + "security/ir.model.access.csv", "views/base_substate_type_views.xml", "views/base_substate_value_views.xml", "views/base_substate_views.xml", diff --git a/base_substate/models/base_substate.py b/base_substate/models/base_substate.py index 5c14994ec5..a312488942 100644 --- a/base_substate/models/base_substate.py +++ b/base_substate/models/base_substate.py @@ -15,15 +15,18 @@ class BaseSubstateType(models.Model): - model: sale.order - target_state_field: state """ + _name = "base.substate.type" - _description = 'Base Substate Type' - _order = 'name asc, model asc' + _description = "Base Substate Type" + _order = "name asc, model asc" name = fields.Char(required=True, translate=True) - model = fields.Selection(selection=[], string='Apply on', required=True) + model = fields.Selection(selection=[], string="Apply on", required=True) target_state_field = fields.Char( - required=True, help='Technical target state field name.' - ' Ex for sale order "state" for other "status" ... ') + required=True, + help="Technical target state field name." + ' Ex for sale order "state" for other "status" ... ', + ) class TargetStateValue(models.Model): @@ -32,27 +35,32 @@ class TargetStateValue(models.Model): Data in this model should be created by import as technical data in specific module ex : sale_subsatate """ + _name = "target.state.value" - _description = 'Target State Value' - _order = 'name asc' + _description = "Target State Value" + _order = "name asc" name = fields.Char( - 'Target state Name', + "Target state Name", required=True, translate=True, - help='Target state translateble name.\n' - 'Ex: for sale order "Quotation", "Sale order", "Locked"...') + help="Target state translateble name.\n" + 'Ex: for sale order "Quotation", "Sale order", "Locked"...', + ) base_substate_type_id = fields.Many2one( - 'base.substate.type', - string='Substate Type', - ondelete='restrict', + "base.substate.type", string="Substate Type", ondelete="restrict", ) target_state_value = fields.Char( - required=True, help='Technical target state value.\n' - 'Ex: for sale order "draft", "sale", "done", ...') - model = fields.Selection(related='base_substate_type_id.model', - store=True, readonly=True, - help="Model for technical use") + required=True, + help="Technical target state value.\n" + 'Ex: for sale order "draft", "sale", "done", ...', + ) + model = fields.Selection( + related="base_substate_type_id.model", + store=True, + readonly=True, + help="Model for technical use", + ) class BaseSubstate(models.Model): @@ -64,26 +72,29 @@ class BaseSubstate(models.Model): "Won" and "Lost". We can also send mail when the susbstate is reached. """ + _name = "base.substate" - _description = 'Base Substate' - _order = 'active desc, sequence asc' + _description = "Base Substate" + _order = "active desc, sequence asc" - name = fields.Char('Substate Name', required=True, translate=True) + name = fields.Char("Substate Name", required=True, translate=True) description = fields.Text(translate=True) sequence = fields.Integer( - index=True, - help="Gives the sequence order when applying the default substate", + index=True, help="Gives the sequence order when applying the default substate", ) target_state_value_id = fields.Many2one( - 'target.state.value', - string='Target State Value', - ondelete='restrict') + "target.state.value", string="Target State Value", ondelete="restrict" + ) active = fields.Boolean(default=True) mail_template_id = fields.Many2one( - 'mail.template', - string='Email Template', + "mail.template", + string="Email Template", help="If set, an email will be sent to the partner " - "when the object reaches this substate.") - model = fields.Selection(related='target_state_value_id.model', - store=True, readonly=True, - help="Model for technical use") + "when the object reaches this substate.", + ) + model = fields.Selection( + related="target_state_value_id.model", + store=True, + readonly=True, + help="Model for technical use", + ) diff --git a/base_substate/models/base_substate_mixin.py b/base_substate/models/base_substate_mixin.py index 42cb60f987..66961006c8 100644 --- a/base_substate/models/base_substate_mixin.py +++ b/base_substate/models/base_substate_mixin.py @@ -1,20 +1,23 @@ # Copyright 2020 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import ValidationError class BaseSubstateMixin(models.AbstractModel): _name = "base.substate.mixin" - _description = 'BaseSubstate Mixin' + _description = "BaseSubstate Mixin" def _get_default_substate_id(self, state_val=False): """ Gives default substate_id """ search_domain = self._get_default_substate_domain(state_val) # perform search, return the first found - return self.env['base.substate'].search(search_domain, - order='sequence', limit=1).id + return ( + self.env["base.substate"] + .search(search_domain, order="sequence", limit=1) + .id + ) def _get_default_substate_domain(self, state_val=False): """ Override this method @@ -27,53 +30,52 @@ def _get_default_substate_domain(self, state_val=False): if self and not state_val and state_field in self._fields: state_val = self[state_field] - domain = [('target_state_value_id.target_state_value', '=', state_val)] - domain += [('target_state_value_id.base_substate_type_id', - '=', substate_type.id)] + domain = [("target_state_value_id.target_state_value", "=", state_val)] + domain += [ + ("target_state_value_id.base_substate_type_id", "=", substate_type.id) + ] return domain def _get_default_state_value(self,): """ Override this method to change state_value """ - return 'draft' + return "draft" def _get_substate_type(self,): """ Override this method to change substate_type (get by xml id for example) """ - return self.env['base.substate.type'].search( - [('model', '=', self._name)], limit=1) + return self.env["base.substate.type"].search( + [("model", "=", self._name)], limit=1 + ) substate_id = fields.Many2one( - 'base.substate', - string='Sub State', - ondelete='restrict', + "base.substate", + string="Sub State", + ondelete="restrict", default=lambda self: self._get_default_substate_id(), - track_visibility='onchange', + track_visibility="onchange", index=True, - domain=lambda self: [ - ('model', - '=', - self._name)], - copy=False) + domain=lambda self: [("model", "=", self._name)], + copy=False, + ) - @api.constrains('substate_id') + @api.constrains("substate_id") def check_substate_id_consistency(self): for mixin_obj in self: - if (mixin_obj.substate_id and - mixin_obj.substate_id.model != self._name): + if mixin_obj.substate_id and mixin_obj.substate_id.model != self._name: raise ValidationError( - _("This substate is not define for this object but for %s" - ) % - mixin_obj.substate_id.model) + _("This substate is not define for this object but for %s") + % mixin_obj.substate_id.model + ) def _update_before_write_create(self, values): substate_type = self._get_substate_type() state_field = substate_type.target_state_field - if values.get(state_field) and not values.get('substate_id'): + if values.get(state_field) and not values.get("substate_id"): state_val = values.get(state_field) - values['substate_id'] = self._get_default_substate_id(state_val) + values["substate_id"] = self._get_default_substate_id(state_val) return values @api.multi diff --git a/base_substate/readme/USAGE.rst b/base_substate/readme/USAGE.rst index e4bfecbcbb..1b8849ea93 100644 --- a/base_substate/readme/USAGE.rst +++ b/base_substate/readme/USAGE.rst @@ -1 +1 @@ -#. You must install an application module depending this one (for example sale_substate) +#. You must install an application module depending this one (for example sale_substate) diff --git a/base_substate/security/base_substate_security.xml b/base_substate/security/base_substate_security.xml index 793ef434d2..4f98ee90ea 100644 --- a/base_substate/security/base_substate_security.xml +++ b/base_substate/security/base_substate_security.xml @@ -1,9 +1,7 @@ - + - Substate manager - + - diff --git a/base_substate/tests/__init__.py b/base_substate/tests/__init__.py index bc0f1b9e60..996498a1b5 100644 --- a/base_substate/tests/__init__.py +++ b/base_substate/tests/__init__.py @@ -1,4 +1,3 @@ - from . import models_mixin from . import sale_test from . import test_base_substate diff --git a/base_substate/tests/models_mixin.py b/base_substate/tests/models_mixin.py index 80d4fb8391..a238132e61 100644 --- a/base_substate/tests/models_mixin.py +++ b/base_substate/tests/models_mixin.py @@ -81,15 +81,13 @@ def _test_teardown_model(cls, env): # here we must remove the model from list of children of inherited # models parents = cls._inherit - parents = [ - parents] if isinstance(parents, str) else (parents or []) + parents = [parents] if isinstance(parents, str) else (parents or []) # keep a copy to be sure to not modify the original _inherit parents = list(parents) parents.extend(cls._inherits.keys()) parents.append("base") funcs = [ - attrgetter(kind + "_children") for kind in - ["_inherits", "_inherit"] + attrgetter(kind + "_children") for kind in ["_inherits", "_inherit"] ] for parent in parents: for func in funcs: @@ -100,8 +98,7 @@ def _test_teardown_model(cls, env): children.remove(cls._name) def _test_get_model_id(self): - self.env.cr.execute( - "SELECT id FROM ir_model WHERE model = %s", (self._name,)) + self.env.cr.execute("SELECT id FROM ir_model WHERE model = %s", (self._name,)) res = self.env.cr.fetchone() return res[0] if res else None diff --git a/base_substate/tests/sale_test.py b/base_substate/tests/sale_test.py index 618bcf68ed..4e59e2c36c 100644 --- a/base_substate/tests/sale_test.py +++ b/base_substate/tests/sale_test.py @@ -6,28 +6,28 @@ class SaleTest(models.Model, TestMixin): - _inherit = 'base.substate.mixin' + _inherit = "base.substate.mixin" _name = "base.substate.test.sale" _description = "Base substate Test Model" name = fields.Char(required=True) - user_id = fields.Many2one('res.users', string='Responsible') + user_id = fields.Many2one("res.users", string="Responsible") state = fields.Selection( - [('draft', 'New'), ('cancel', 'Cancelled'), - ('sale', 'Sale'), - ('done', 'Done')], - string="Status", readonly=True, default='draft') + [("draft", "New"), ("cancel", "Cancelled"), ("sale", "Sale"), ("done", "Done")], + string="Status", + readonly=True, + default="draft", + ) active = fields.Boolean(default=True) - partner_id = fields.Many2one('res.partner', string='Partner') + partner_id = fields.Many2one("res.partner", string="Partner") line_ids = fields.One2many( - comodel_name='base.substate.test.sale.line', - inverse_name='sale_id', + comodel_name="base.substate.test.sale.line", + inverse_name="sale_id", context={"active_test": False}, ) - amount_total = fields.Float( - compute='_compute_amount_total', store=True) + amount_total = fields.Float(compute="_compute_amount_total", store=True) - @api.depends('line_ids') + @api.depends("line_ids") def _compute_amount_total(cls): for record in cls: for line in record.line_ids: @@ -35,12 +35,12 @@ def _compute_amount_total(cls): @api.multi def button_confirm(cls): - cls.write({'state': 'sale'}) + cls.write({"state": "sale"}) return True @api.multi def button_cancel(cls): - cls.write({'state': 'cancel'}) + cls.write({"state": "cancel"}) class LineTest(models.Model, TestMixin): @@ -49,8 +49,8 @@ class LineTest(models.Model, TestMixin): name = fields.Char() sale_id = fields.Many2one( - comodel_name='base.substate.test.sale', - ondelete='cascade', + comodel_name="base.substate.test.sale", + ondelete="cascade", context={"active_test": False}, ) qty = fields.Float() diff --git a/base_substate/tests/test_base_substate.py b/base_substate/tests/test_base_substate.py index ec8b07f4b9..b12ea2382d 100644 --- a/base_substate/tests/test_base_substate.py +++ b/base_substate/tests/test_base_substate.py @@ -2,74 +2,91 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo.tests import common -from .sale_test import SaleTest, LineTest + +from .sale_test import LineTest, SaleTest @common.at_install(False) @common.post_install(True) class TestBaseSubstate(common.SavepointCase): - @classmethod def setUpClass(cls): super(TestBaseSubstate, cls).setUpClass() SaleTest._test_setup_models(cls.env, [SaleTest, LineTest]) LineTest._test_setup_model(cls.env) - cls.substate_test_sale = cls.env['base.substate.test.sale'] - cls.substate_test_sale_line = cls.env['base.substate.test.sale.line'] - - cls.base_substate = cls.env['base.substate.mixin'] - cls.substate_type = cls.env['base.substate.type'] - - cls.substate_type._fields['model'].selection.append( - ('base.substate.test.sale', 'Sale Order')) - - cls.substate_type = cls.env['base.substate.type'].create({ - 'name': "Sale", - 'model': "base.substate.test.sale", - 'target_state_field': "state", - }) - - cls.substate_val_quotation = cls.env['target.state.value'].create({ - 'name': "Quotation", - 'base_substate_type_id': cls.substate_type.id, - 'target_state_value': "draft", - }) - - cls.substate_val_sale = cls.env['target.state.value'].create({ - 'name': "Sale order", - 'base_substate_type_id': cls.substate_type.id, - 'target_state_value': "sale", - }) - cls.substate_under_negotiation = cls.env['base.substate'].create({ - 'name': "Under negotiation", - 'sequence': 1, - 'target_state_value_id': cls.substate_val_quotation.id, - }) - - cls.substate_won = cls.env['base.substate'].create({ - 'name': "Won", - 'sequence': 1, - 'target_state_value_id': cls.substate_val_quotation.id, - }) - - cls.substate_wait_docs = cls.env['base.substate'].create({ - 'name': "Waiting for legal documents", - 'sequence': 2, - 'target_state_value_id': cls.substate_val_sale.id, - }) - - cls.substate_valid_docs = cls.env['base.substate'].create({ - 'name': "To validate legal documents", - 'sequence': 3, - 'target_state_value_id': cls.substate_val_sale.id, - }) - - cls.substate_in_delivering = cls.env['base.substate'].create({ - 'name': "In delivering", - 'sequence': 4, - 'target_state_value_id': cls.substate_val_sale.id, - }) + cls.substate_test_sale = cls.env["base.substate.test.sale"] + cls.substate_test_sale_line = cls.env["base.substate.test.sale.line"] + + cls.base_substate = cls.env["base.substate.mixin"] + cls.substate_type = cls.env["base.substate.type"] + + cls.substate_type._fields["model"].selection.append( + ("base.substate.test.sale", "Sale Order") + ) + + cls.substate_type = cls.env["base.substate.type"].create( + { + "name": "Sale", + "model": "base.substate.test.sale", + "target_state_field": "state", + } + ) + + cls.substate_val_quotation = cls.env["target.state.value"].create( + { + "name": "Quotation", + "base_substate_type_id": cls.substate_type.id, + "target_state_value": "draft", + } + ) + + cls.substate_val_sale = cls.env["target.state.value"].create( + { + "name": "Sale order", + "base_substate_type_id": cls.substate_type.id, + "target_state_value": "sale", + } + ) + cls.substate_under_negotiation = cls.env["base.substate"].create( + { + "name": "Under negotiation", + "sequence": 1, + "target_state_value_id": cls.substate_val_quotation.id, + } + ) + + cls.substate_won = cls.env["base.substate"].create( + { + "name": "Won", + "sequence": 1, + "target_state_value_id": cls.substate_val_quotation.id, + } + ) + + cls.substate_wait_docs = cls.env["base.substate"].create( + { + "name": "Waiting for legal documents", + "sequence": 2, + "target_state_value_id": cls.substate_val_sale.id, + } + ) + + cls.substate_valid_docs = cls.env["base.substate"].create( + { + "name": "To validate legal documents", + "sequence": 3, + "target_state_value_id": cls.substate_val_sale.id, + } + ) + + cls.substate_in_delivering = cls.env["base.substate"].create( + { + "name": "In delivering", + "sequence": 4, + "target_state_value_id": cls.substate_val_sale.id, + } + ) @classmethod def tearDownClass(cls): @@ -78,27 +95,26 @@ def tearDownClass(cls): super().tearDownClass() def test_sale_order_substate(self): - partner = self.env.ref('base.res_partner_1') - so_test1 = self.substate_test_sale.create({ - 'name': 'Test base substate to basic sale', - 'partner_id': partner.id, - 'line_ids': [(0, 0, { - 'name': "line test", - 'amount': 120.0, - 'qty': 1.5, - })], - }) - self.assertTrue(so_test1.state == 'draft') - self.assertTrue(so_test1.substate_id == - self.substate_under_negotiation) + partner = self.env.ref("base.res_partner_1") + so_test1 = self.substate_test_sale.create( + { + "name": "Test base substate to basic sale", + "partner_id": partner.id, + "line_ids": [ + (0, 0, {"name": "line test", "amount": 120.0, "qty": 1.5,}) + ], + } + ) + self.assertTrue(so_test1.state == "draft") + self.assertTrue(so_test1.substate_id == self.substate_under_negotiation) # Test that validation of sale order change substate_id so_test1.button_confirm() - self.assertTrue(so_test1.state == 'sale') + self.assertTrue(so_test1.state == "sale") self.assertTrue(so_test1.substate_id == self.substate_wait_docs) # Test that substate_id is set to false if # there is not substate corresponding to state so_test1.button_cancel() - self.assertTrue(so_test1.state == 'cancel') + self.assertTrue(so_test1.state == "cancel") self.assertTrue(not so_test1.substate_id) diff --git a/base_substate/views/base_substate_type_views.xml b/base_substate/views/base_substate_type_views.xml index ef8bfbffa9..8abc769d45 100644 --- a/base_substate/views/base_substate_type_views.xml +++ b/base_substate/views/base_substate_type_views.xml @@ -1,79 +1,86 @@ - + - - base.substate.type - - - - - - - - - - - base.substate.type - -
- -
-
- - - - + + base.substate.type + + + + + + + + + + base.substate.type + + + +
+
+ + + + + -
-
-
-
-
- - - base.substate.type - - - - - - - - - - - Sub State Type - ir.actions.act_window - base.substate.type - form - tree,form - - [] - {} - - - - - - form - - - - - - - tree - - - - + + + + + + base.substate.type + + + + + + + + + + Sub State Type + ir.actions.act_window + base.substate.type + form + tree,form + + [] + {} + + + + + form + + + + + + tree + + + +
diff --git a/base_substate/views/base_substate_value_views.xml b/base_substate/views/base_substate_value_views.xml index be3dad089b..9e8b3b8df7 100644 --- a/base_substate/views/base_substate_value_views.xml +++ b/base_substate/views/base_substate_value_views.xml @@ -1,76 +1,84 @@ - + - - target.state.value - - - - - - - - - - - target.state.value - -
- -
-
- - - - + + target.state.value + + + + + + + + + + target.state.value + + + +
+
+ + + + + -
-
-
-
-
- - - target.state.value - - - - - - - - - - - Target State Value - ir.actions.act_window - target.state.value - form - tree,form - - [] - {} - - - - - - form - - - - - - - tree - - - - + + + + + + target.state.value + + + + + + + + + + Target State Value + ir.actions.act_window + target.state.value + form + tree,form + + [] + {} + + + + + form + + + + + + tree + + +
diff --git a/base_substate/views/base_substate_views.xml b/base_substate/views/base_substate_views.xml index f52d10969b..e404f8f3c9 100644 --- a/base_substate/views/base_substate_views.xml +++ b/base_substate/views/base_substate_views.xml @@ -1,84 +1,90 @@ - + - - base.substate - - - - - - - - - - - - - base.substate - -
- -
- -
-
-
- - - - - - - + + base.substate + + + + + + + + + + + + base.substate + + + +
+ +
+
+
+ + + + + + + + -
-
-
-
-
- - - base.substate - - - - - - - - - Base Substate - ir.actions.act_window - base.substate - form - tree,form - - [] - {} - - - - - - form - - - - - - - tree - - - - + + + + + + base.substate + + + + + + + + Base Substate + ir.actions.act_window + base.substate + form + tree,form + + [] + {} + + + + + form + + + + + + tree + + +
From e2ab1a6a958885041c2ba87984c53cb9305cbae6 Mon Sep 17 00:00:00 2001 From: Kitti U Date: Sun, 30 Aug 2020 11:04:10 +0700 Subject: [PATCH 024/161] [13.0][MIG] base_substate --- base_substate/README.rst | 15 ++++---- base_substate/__manifest__.py | 2 +- base_substate/i18n/base_substate.pot | 29 ++++++++++----- base_substate/models/base_substate_mixin.py | 37 ++++++++++++++++++- base_substate/readme/CONTRIBUTORS.rst | 1 + base_substate/readme/DESCRIPTION.rst | 2 +- base_substate/readme/USAGE.rst | 2 +- base_substate/static/description/index.html | 11 +++--- base_substate/tests/sale_test.py | 14 +++---- base_substate/tests/test_base_substate.py | 2 +- .../views/base_substate_type_views.xml | 1 - .../views/base_substate_value_views.xml | 1 - base_substate/views/base_substate_views.xml | 1 - 13 files changed, 81 insertions(+), 37 deletions(-) diff --git a/base_substate/README.rst b/base_substate/README.rst index e9772bdacf..e03817206d 100644 --- a/base_substate/README.rst +++ b/base_substate/README.rst @@ -14,13 +14,13 @@ Base Sub State :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/12.0/base_substate + :target: https://github.com/OCA/server-ux/tree/13.0/base_substate :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-12-0/server-ux-12-0-base_substate + :target: https://translation.odoo-community.org/projects/server-ux-13-0/server-ux-13-0-base_substate :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/250/12.0 + :target: https://runbot.odoo-community.org/runbot/250/13.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -36,7 +36,7 @@ example: * We can also send mail when the susbstate is reached. It is not useful for itself. You can see an example of implementation -in the 'sale_substate' module. (sale-workflow repository). +in the 'purchase_substate' module. (purchase-workflow repository). **Table of contents** @@ -46,7 +46,7 @@ in the 'sale_substate' module. (sale-workflow repository). Usage ===== -#. You must install an application module depending this one (for example sale_substate) +#. You must install an application module depending this one (for example purchase_substate) Bug Tracker =========== @@ -54,7 +54,7 @@ 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 smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -70,6 +70,7 @@ Contributors ~~~~~~~~~~~~ * Mourad EL HADJ MIMOUNE +* Kitti U. Maintainers ~~~~~~~~~~~ @@ -84,6 +85,6 @@ 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. +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_substate/__manifest__.py b/base_substate/__manifest__.py index ddc8c4ce96..dd8219d50b 100644 --- a/base_substate/__manifest__.py +++ b/base_substate/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Base Sub State", - "version": "12.0.1.0.0", + "version": "13.0.1.0.0", "category": "Tools", "author": "Akretion, " "Odoo Community Association (OCA)", "website": "https://github.com/OCA/sale-workflow/", diff --git a/base_substate/i18n/base_substate.pot b/base_substate/i18n/base_substate.pot index 218c1a4cc7..7b28bc5cca 100644 --- a/base_substate/i18n/base_substate.pot +++ b/base_substate/i18n/base_substate.pot @@ -1,12 +1,12 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * base_substate +# * base_substate # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" +"Project-Id-Version: Odoo Server 13.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: <>\n" +"Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -91,7 +91,9 @@ msgstr "" #. module: base_substate #: model:ir.model.fields,help:base_substate.field_base_substate__mail_template_id -msgid "If set, an email will be sent to the partner when the object reaches this substate." +msgid "" +"If set, an email will be sent to the partner when the object reaches this " +"substate." msgstr "" #. module: base_substate @@ -188,24 +190,33 @@ msgstr "" #. module: base_substate #: model:ir.model.fields,help:base_substate.field_target_state_value__name -msgid "Target state translateble name.\n" +msgid "" +"Target state translateble name.\n" "Ex: for sale order \"Quotation\", \"Sale order\", \"Locked\"..." msgstr "" #. module: base_substate #: model:ir.model.fields,help:base_substate.field_base_substate_type__target_state_field -msgid "Technical target state field name. Ex for sale order \"state\" for other \"status\" ... " +msgid "" +"Technical target state field name. Ex for sale order \"state\" for other " +"\"status\" ... " msgstr "" #. module: base_substate #: model:ir.model.fields,help:base_substate.field_target_state_value__target_state_value -msgid "Technical target state value.\n" +msgid "" +"Technical target state value.\n" "Ex: for sale order \"draft\", \"sale\", \"done\", ..." msgstr "" #. module: base_substate -#: code:addons/base_substate/models/base_substate_mixin.py:67 +#: code:addons/base_substate/models/base_substate_mixin.py:0 #, python-format -msgid "This substate is not define for this object but for %s" +msgid "The substate \"%s\" is not define for the state \"%s\" but for \"%s\" " msgstr "" +#. module: base_substate +#: code:addons/base_substate/models/base_substate_mixin.py:0 +#, python-format +msgid "This substate is not define for this object but for %s" +msgstr "" diff --git a/base_substate/models/base_substate_mixin.py b/base_substate/models/base_substate_mixin.py index 66961006c8..cb994d3e0b 100644 --- a/base_substate/models/base_substate_mixin.py +++ b/base_substate/models/base_substate_mixin.py @@ -8,6 +8,42 @@ class BaseSubstateMixin(models.AbstractModel): _name = "base.substate.mixin" _description = "BaseSubstate Mixin" + _state_field = "state" + + @api.constrains("substate_id", _state_field) + def check_substate_id_value(self): + rec_states = dict(self._fields[self._state_field].selection) + for rec in self: + target_state = rec.substate_id.target_state_value_id.target_state_value + if rec.substate_id and rec.state != target_state: + raise ValidationError( + _( + 'The substate "%s" is not define for the state' + ' "%s" but for "%s" ' + ) + % ( + rec.substate_id.name, + _(rec_states[rec.state]), + _(rec_states[target_state]), + ) + ) + + def _track_template(self, tracking): + res = super()._track_template(tracking) + first_rec = self[0] + changes, tracking_value_ids = tracking[first_rec.id] + if "substate_id" in changes and first_rec.substate_id.mail_template_id: + res["substate_id"] = ( + first_rec.substate_id.mail_template_id, + { + "auto_delete_message": True, + "subtype_id": self.env["ir.model.data"].xmlid_to_res_id( + "mail.mt_note" + ), + "notif_layout": "mail.mail_notification_light", + }, + ) + return res def _get_default_substate_id(self, state_val=False): """ Gives default substate_id """ @@ -78,7 +114,6 @@ def _update_before_write_create(self, values): values["substate_id"] = self._get_default_substate_id(state_val) return values - @api.multi def write(self, values): values = self._update_before_write_create(values) res = super().write(values) diff --git a/base_substate/readme/CONTRIBUTORS.rst b/base_substate/readme/CONTRIBUTORS.rst index f55657f6b9..4bb895c6ca 100644 --- a/base_substate/readme/CONTRIBUTORS.rst +++ b/base_substate/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * Mourad EL HADJ MIMOUNE +* Kitti U. diff --git a/base_substate/readme/DESCRIPTION.rst b/base_substate/readme/DESCRIPTION.rst index 290681551d..3268944e41 100644 --- a/base_substate/readme/DESCRIPTION.rst +++ b/base_substate/readme/DESCRIPTION.rst @@ -9,4 +9,4 @@ example: * We can also send mail when the susbstate is reached. It is not useful for itself. You can see an example of implementation -in the 'sale_substate' module. (sale-workflow repository). +in the 'purchase_substate' module. (purchase-workflow repository). diff --git a/base_substate/readme/USAGE.rst b/base_substate/readme/USAGE.rst index 1b8849ea93..fca986c290 100644 --- a/base_substate/readme/USAGE.rst +++ b/base_substate/readme/USAGE.rst @@ -1 +1 @@ -#. You must install an application module depending this one (for example sale_substate) +#. You must install an application module depending this one (for example purchase_substate) diff --git a/base_substate/static/description/index.html b/base_substate/static/description/index.html index 6511a08abd..2b0c25f672 100644 --- a/base_substate/static/description/index.html +++ b/base_substate/static/description/index.html @@ -367,7 +367,7 @@

Base Sub State

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

This module provide abstract models to manage customizable substates to be applied on different models (sale order, purchase, …).

@@ -378,7 +378,7 @@

example:

  • We can also send mail when the susbstate is reached.
  • It is not useful for itself. You can see an example of implementation -in the ‘sale_substate’ module. (sale-workflow repository).

    +in the ‘purchase_substate’ module. (purchase-workflow repository).

    Table of contents

      @@ -395,7 +395,7 @@

      example:

      Usage

        -
      1. You must install an application module depending this one (for example sale_substate)
      2. +
      3. You must install an application module depending this one (for example purchase_substate)
      @@ -403,7 +403,7 @@

      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 smashing it by providing a detailed and welcomed -feedback.

      +feedback.

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

      @@ -418,6 +418,7 @@

      Authors

      Contributors

      @@ -427,7 +428,7 @@

      Maintainers

      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.

      +

      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_substate/tests/sale_test.py b/base_substate/tests/sale_test.py index 4e59e2c36c..c3d80cc07d 100644 --- a/base_substate/tests/sale_test.py +++ b/base_substate/tests/sale_test.py @@ -28,19 +28,17 @@ class SaleTest(models.Model, TestMixin): amount_total = fields.Float(compute="_compute_amount_total", store=True) @api.depends("line_ids") - def _compute_amount_total(cls): - for record in cls: + def _compute_amount_total(self): + for record in self: for line in record.line_ids: record.amount_total += line.amount * line.qty - @api.multi - def button_confirm(cls): - cls.write({"state": "sale"}) + def button_confirm(self): + self.write({"state": "sale"}) return True - @api.multi - def button_cancel(cls): - cls.write({"state": "cancel"}) + def button_cancel(self): + self.write({"state": "cancel"}) class LineTest(models.Model, TestMixin): diff --git a/base_substate/tests/test_base_substate.py b/base_substate/tests/test_base_substate.py index b12ea2382d..25f855b6f8 100644 --- a/base_substate/tests/test_base_substate.py +++ b/base_substate/tests/test_base_substate.py @@ -101,7 +101,7 @@ def test_sale_order_substate(self): "name": "Test base substate to basic sale", "partner_id": partner.id, "line_ids": [ - (0, 0, {"name": "line test", "amount": 120.0, "qty": 1.5,}) + (0, 0, {"name": "line test", "amount": 120.0, "qty": 1.5}) ], } ) diff --git a/base_substate/views/base_substate_type_views.xml b/base_substate/views/base_substate_type_views.xml index 8abc769d45..eb7d3f4b47 100644 --- a/base_substate/views/base_substate_type_views.xml +++ b/base_substate/views/base_substate_type_views.xml @@ -47,7 +47,6 @@ Sub State Type ir.actions.act_window base.substate.type - form tree,form [] diff --git a/base_substate/views/base_substate_value_views.xml b/base_substate/views/base_substate_value_views.xml index 9e8b3b8df7..482f41aa73 100644 --- a/base_substate/views/base_substate_value_views.xml +++ b/base_substate/views/base_substate_value_views.xml @@ -51,7 +51,6 @@ Target State Value ir.actions.act_window target.state.value - form tree,form [] diff --git a/base_substate/views/base_substate_views.xml b/base_substate/views/base_substate_views.xml index e404f8f3c9..80805a3180 100644 --- a/base_substate/views/base_substate_views.xml +++ b/base_substate/views/base_substate_views.xml @@ -63,7 +63,6 @@ Base Substate ir.actions.act_window base.substate - form tree,form [] From 399f174a5f28031da0edf18c3bb9052260695c66 Mon Sep 17 00:00:00 2001 From: newtratip Date: Sat, 8 May 2021 14:54:11 +0700 Subject: [PATCH 025/161] [13.0][FIX] base_substate: Fix archived button --- base_substate/__manifest__.py | 2 +- base_substate/i18n/base_substate.pot | 5 +++++ base_substate/views/base_substate_views.xml | 18 ++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/base_substate/__manifest__.py b/base_substate/__manifest__.py index dd8219d50b..dca677fa24 100644 --- a/base_substate/__manifest__.py +++ b/base_substate/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Base Sub State", - "version": "13.0.1.0.0", + "version": "13.0.1.1.0", "category": "Tools", "author": "Akretion, " "Odoo Community Association (OCA)", "website": "https://github.com/OCA/sale-workflow/", diff --git a/base_substate/i18n/base_substate.pot b/base_substate/i18n/base_substate.pot index 7b28bc5cca..24b2b64fe4 100644 --- a/base_substate/i18n/base_substate.pot +++ b/base_substate/i18n/base_substate.pot @@ -25,6 +25,11 @@ msgstr "" msgid "Apply on" msgstr "" +#. module: base_substate +#: model_terms:ir.ui.view,arch_db:base_substate.base_substate_view_form +msgid "Archived" +msgstr "" + #. module: base_substate #: model:ir.actions.act_window,name:base_substate.act_open_base_substate_view #: model:ir.model,name:base_substate.model_base_substate diff --git a/base_substate/views/base_substate_views.xml b/base_substate/views/base_substate_views.xml index 80805a3180..3f7625249a 100644 --- a/base_substate/views/base_substate_views.xml +++ b/base_substate/views/base_substate_views.xml @@ -19,16 +19,14 @@
    -
    - -
    +
    + +