OCA-git-bot
4 years ago
23 changed files with 905 additions and 198 deletions
-
74base_comment_template/README.rst
-
13base_comment_template/__manifest__.py
-
135base_comment_template/i18n/base_comment_template.pot
-
181base_comment_template/i18n/es.po
-
29base_comment_template/migrations/14.0.2.0.0/post-migration.py
-
30base_comment_template/migrations/14.0.2.0.0/pre-migration.py
-
5base_comment_template/models/__init__.py
-
88base_comment_template/models/base_comment_template.py
-
48base_comment_template/models/comment.py
-
45base_comment_template/models/comment_template.py
-
33base_comment_template/models/ir_model.py
-
16base_comment_template/models/res_partner.py
-
8base_comment_template/readme/CONFIGURE.rst
-
9base_comment_template/readme/CONTRIBUTORS.rst
-
18base_comment_template/readme/DESCRIPTION.rst
-
31base_comment_template/readme/USAGE.rst
-
1base_comment_template/security/ir.model.access.csv
-
5base_comment_template/security/security.xml
-
92base_comment_template/static/description/index.html
-
34base_comment_template/tests/fake_models.py
-
106base_comment_template/tests/test_base_comment_template.py
-
72base_comment_template/views/base_comment_template_view.xml
-
28base_comment_template/views/res_partner_view.xml
@ -0,0 +1,29 @@ |
|||||
|
# Copyright 2021 Tecnativa - Víctor Martínez |
||||
|
# Copyright 2021 Tecnativa - Pedro M. Baeza |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
||||
|
from openupgradelib import openupgrade |
||||
|
|
||||
|
from odoo.tools import parse_version |
||||
|
|
||||
|
|
||||
|
@openupgrade.migrate() |
||||
|
def migrate(env, version): |
||||
|
if parse_version(version) == parse_version("14.0.1.0.0"): |
||||
|
openupgrade.logged_query( |
||||
|
env.cr, |
||||
|
""" |
||||
|
INSERT INTO base_comment_template_res_partner_rel |
||||
|
(res_partner_id, base_comment_template_id) |
||||
|
SELECT SPLIT_PART(ip.res_id, ',', 2)::int AS res_partner_id, |
||||
|
SPLIT_PART(ip.value_reference, ',', 2)::int AS base_comment_template_id |
||||
|
FROM ir_property ip |
||||
|
JOIN ir_model_fields imf ON ip.fields_id = imf.id |
||||
|
JOIN res_partner rp ON rp.id = SPLIT_PART(ip.res_id, ',', 2)::int |
||||
|
JOIN base_comment_template bct |
||||
|
ON bct.id = SPLIT_PART(ip.value_reference, ',', 2)::int |
||||
|
WHERE imf.name = 'property_comment_template_id' |
||||
|
AND imf.model = 'res.partner' |
||||
|
AND ip.res_id IS NOT NULL |
||||
|
ON CONFLICT DO NOTHING |
||||
|
""", |
||||
|
) |
@ -0,0 +1,30 @@ |
|||||
|
# Copyright 2021 Tecnativa - Víctor Martínez |
||||
|
# Copyright 2021 Tecnativa - Pedro M: Baeza |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
||||
|
from openupgradelib import openupgrade |
||||
|
|
||||
|
from odoo.tools import parse_version |
||||
|
|
||||
|
field_renames = [ |
||||
|
("base.comment.template", "base_comment_template", "priority", "sequence"), |
||||
|
] |
||||
|
|
||||
|
|
||||
|
@openupgrade.migrate() |
||||
|
def migrate(env, version): |
||||
|
if parse_version(version) == parse_version("14.0.1.0.0"): |
||||
|
openupgrade.rename_fields(env, field_renames) |
||||
|
if openupgrade.table_exists(env.cr, "base_comment_template_res_partner_rel"): |
||||
|
# Swap column names, as they were incorrect |
||||
|
env.cr.execute( |
||||
|
"ALTER TABLE base_comment_template_res_partner_rel " |
||||
|
"RENAME base_comment_template_id TO temp" |
||||
|
) |
||||
|
env.cr.execute( |
||||
|
"ALTER TABLE base_comment_template_res_partner_rel " |
||||
|
"RENAME res_partner_id TO base_comment_template_id" |
||||
|
) |
||||
|
env.cr.execute( |
||||
|
"ALTER TABLE base_comment_template_res_partner_rel " |
||||
|
"RENAME temp TO res_partner_id" |
||||
|
) |
@ -1,3 +1,4 @@ |
|||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
from . import comment |
|
||||
|
from . import base_comment_template |
||||
|
from . import comment_template |
||||
from . import res_partner |
from . import res_partner |
||||
|
from . import ir_model |
@ -0,0 +1,88 @@ |
|||||
|
# Copyright 2014 Guewen Baconnier (Camptocamp SA) |
||||
|
# Copyright 2013-2014 Nicolas Bessi (Camptocamp SA) |
||||
|
# Copyright 2020 NextERP Romania SRL |
||||
|
# Copyright 2021 Tecnativa - Víctor Martínez |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class BaseCommentTemplate(models.Model): |
||||
|
"""Comment templates printed on reports""" |
||||
|
|
||||
|
_name = "base.comment.template" |
||||
|
_description = "Comments Template" |
||||
|
_order = "sequence,id" |
||||
|
|
||||
|
active = fields.Boolean(default=True) |
||||
|
position = fields.Selection( |
||||
|
string="Position on document", |
||||
|
selection=[("before_lines", "Top"), ("after_lines", "Bottom")], |
||||
|
required=True, |
||||
|
default="before_lines", |
||||
|
help="This field allows to select the position of the comment on reports.", |
||||
|
) |
||||
|
name = fields.Char( |
||||
|
string="Name", |
||||
|
translate=True, |
||||
|
required=True, |
||||
|
help="Name/description of this comment template", |
||||
|
) |
||||
|
text = fields.Html( |
||||
|
string="Template", |
||||
|
translate=True, |
||||
|
required=True, |
||||
|
sanitize=False, |
||||
|
help="This is the text template that will be inserted into reports.", |
||||
|
) |
||||
|
company_id = fields.Many2one( |
||||
|
comodel_name="res.company", |
||||
|
string="Company", |
||||
|
ondelete="cascade", |
||||
|
index=True, |
||||
|
help="If set, the comment template will be available only for the selected " |
||||
|
"company.", |
||||
|
) |
||||
|
partner_ids = fields.Many2many( |
||||
|
comodel_name="res.partner", |
||||
|
relation="base_comment_template_res_partner_rel", |
||||
|
column1="base_comment_template_id", |
||||
|
column2="res_partner_id", |
||||
|
string="Partner", |
||||
|
readonly=True, |
||||
|
help="If set, the comment template will be available only for the selected " |
||||
|
"partner.", |
||||
|
) |
||||
|
model_ids = fields.Many2many( |
||||
|
comodel_name="ir.model", |
||||
|
string="IR Model", |
||||
|
ondelete="cascade", |
||||
|
domain=[ |
||||
|
("is_comment_template", "=", True), |
||||
|
("model", "!=", "comment.template"), |
||||
|
], |
||||
|
required=True, |
||||
|
help="This comment template will be available on this models. " |
||||
|
"You can see here only models allowed to set the coment template.", |
||||
|
) |
||||
|
domain = fields.Char( |
||||
|
string="Filter Domain", |
||||
|
required=True, |
||||
|
default="[]", |
||||
|
help="This comment template will be available only for objects " |
||||
|
"that satisfy the condition", |
||||
|
) |
||||
|
sequence = fields.Integer( |
||||
|
required=True, default=10, help="The smaller number = The higher priority" |
||||
|
) |
||||
|
|
||||
|
def name_get(self): |
||||
|
"""Redefine the name_get method to show the template name with the position.""" |
||||
|
res = [] |
||||
|
for item in self: |
||||
|
name = "{} ({})".format( |
||||
|
item.name, dict(self._fields["position"].selection).get(item.position) |
||||
|
) |
||||
|
if self.env.context.get("comment_template_model_display"): |
||||
|
name += " (%s)" % ", ".join(item.model_ids.mapped("name")) |
||||
|
res.append((item.id, name)) |
||||
|
return res |
@ -1,48 +0,0 @@ |
|||||
# Copyright 2014 Guewen Baconnier (Camptocamp SA) |
|
||||
# Copyright 2013-2014 Nicolas Bessi (Camptocamp SA) |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from odoo import fields, models |
|
||||
|
|
||||
|
|
||||
class BaseCommentTemplate(models.Model): |
|
||||
_name = "base.comment.template" |
|
||||
_description = "Base comment template" |
|
||||
|
|
||||
active = fields.Boolean(default=True) |
|
||||
|
|
||||
name = fields.Char( |
|
||||
string="Comment summary", |
|
||||
required=True, |
|
||||
) |
|
||||
|
|
||||
position = fields.Selection( |
|
||||
selection=[ |
|
||||
("before_lines", "Before lines"), |
|
||||
("after_lines", "After lines"), |
|
||||
], |
|
||||
required=True, |
|
||||
default="before_lines", |
|
||||
help="Position on document", |
|
||||
) |
|
||||
|
|
||||
text = fields.Html( |
|
||||
string="Comment", |
|
||||
translate=True, |
|
||||
required=True, |
|
||||
) |
|
||||
|
|
||||
company_id = fields.Many2one( |
|
||||
"res.company", |
|
||||
string="Company", |
|
||||
help="If set, it'll only be available for this company", |
|
||||
ondelete="cascade", |
|
||||
index=True, |
|
||||
) |
|
||||
|
|
||||
def get_value(self, partner_id=False): |
|
||||
self.ensure_one() |
|
||||
lang = None |
|
||||
if partner_id: |
|
||||
lang = self.env["res.partner"].browse(partner_id).lang |
|
||||
return self.with_context(lang=lang).text |
|
@ -0,0 +1,45 @@ |
|||||
|
# Copyright 2014 Guewen Baconnier (Camptocamp SA) |
||||
|
# Copyright 2013-2014 Nicolas Bessi (Camptocamp SA) |
||||
|
# Copyright 2020 NextERP Romania SRL |
||||
|
# Copyright 2021 Tecnativa - Víctor Martínez |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from odoo import api, fields, models |
||||
|
from odoo.tools.safe_eval import safe_eval |
||||
|
|
||||
|
|
||||
|
class CommentTemplate(models.AbstractModel): |
||||
|
_name = "comment.template" |
||||
|
_description = ( |
||||
|
"base.comment.template to put header and footer " |
||||
|
"in reports based on created comment templates" |
||||
|
) |
||||
|
# This field allows to set any given field that determines the source partner for |
||||
|
# the comment templates downstream. |
||||
|
# E.g.: other models where the partner field is called customer_id. |
||||
|
_comment_template_partner_field_name = "partner_id" |
||||
|
|
||||
|
comment_template_ids = fields.Many2many( |
||||
|
compute="_compute_comment_template_ids", |
||||
|
comodel_name="base.comment.template", |
||||
|
string="Comment Template", |
||||
|
domain=lambda self: [("model_ids.model", "=", self._name)], |
||||
|
store=True, |
||||
|
readonly=False, |
||||
|
) |
||||
|
|
||||
|
@api.depends(_comment_template_partner_field_name) |
||||
|
def _compute_comment_template_ids(self): |
||||
|
for record in self: |
||||
|
partner = record[self._comment_template_partner_field_name] |
||||
|
record.comment_template_ids = [(5,)] |
||||
|
templates = self.env["base.comment.template"].search( |
||||
|
[ |
||||
|
("id", "in", partner.base_comment_template_ids.ids), |
||||
|
("model_ids.model", "=", self._name), |
||||
|
] |
||||
|
) |
||||
|
for template in templates: |
||||
|
if not template.domain or self in self.search( |
||||
|
safe_eval(template.domain) |
||||
|
): |
||||
|
record.comment_template_ids = [(4, template.id)] |
@ -0,0 +1,33 @@ |
|||||
|
# Copyright 2020 NextERP Romania SRL |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class IrModel(models.Model): |
||||
|
_inherit = "ir.model" |
||||
|
|
||||
|
is_comment_template = fields.Boolean( |
||||
|
string="Comment Template", |
||||
|
default=False, |
||||
|
help="Whether this model supports in reports to add comment templates.", |
||||
|
) |
||||
|
|
||||
|
def _reflect_model_params(self, model): |
||||
|
vals = super(IrModel, self)._reflect_model_params(model) |
||||
|
vals["is_comment_template"] = issubclass( |
||||
|
type(model), self.pool["comment.template"] |
||||
|
) |
||||
|
return vals |
||||
|
|
||||
|
@api.model |
||||
|
def _instanciate(self, model_data): |
||||
|
model_class = super(IrModel, self)._instanciate(model_data) |
||||
|
if ( |
||||
|
model_data.get("is_comment_template") |
||||
|
and model_class._name != "comment.template" |
||||
|
): |
||||
|
parents = model_class._inherit or [] |
||||
|
parents = [parents] if isinstance(parents, str) else parents |
||||
|
model_class._inherit = parents + ["comment.template"] |
||||
|
return model_class |
@ -0,0 +1,8 @@ |
|||||
|
Go to *Settings > Technical > Reporting > Comment Templates* and start designing you comment templates. |
||||
|
|
||||
|
This module is the base module for following modules: |
||||
|
|
||||
|
* sale_comment_template |
||||
|
* purchase_comment_template |
||||
|
* invoice_comment_template |
||||
|
* stock_picking_comment_template |
@ -0,0 +1,31 @@ |
|||||
|
#. Go to *Settings* and activate the developer mode. |
||||
|
#. Go to *Settings > Technical > Reporting > Comment Templates*. |
||||
|
#. Create a new record. |
||||
|
#. Define the Company the template is linked or leave default for all companies. |
||||
|
#. Define the Partner the template is linked or leave default for all partners. |
||||
|
#. Define the Model, Domain the template is linked. |
||||
|
#. Define the Position where the template will be printed: |
||||
|
|
||||
|
* above document lines |
||||
|
* below document lines |
||||
|
|
||||
|
You should have at least one template with Default field set, if you choose a Partner the template is deselected as a Default one. |
||||
|
If you create a new template with the same configuration (Model, Domain, Position) and set it as Default, the previous one will be deselected as a default one. |
||||
|
|
||||
|
The template is a html field which will be rendered just like a mail template, so you can use variables like ${object}, ${user}, ${ctx} to add dynamic content. |
||||
|
|
||||
|
Change the report related to the model from configuration and add a statement like: |
||||
|
|
||||
|
<p t-if="o.get_comment_template('before_lines', o.company_id.id, o.partner_id and o.partner_id.id or False)"> |
||||
|
|
||||
|
<span t-raw="o.get_comment_template('before_lines', o.company_id.id, o.partner_id and o.partner_id.id or False)"/> |
||||
|
|
||||
|
</p> |
||||
|
|
||||
|
<p t-if="o.get_comment_template('after_lines', o.company_id.id, o.partner_id and o.partner_id.id or False)"> |
||||
|
|
||||
|
<span t-raw="o.get_comment_template('after_lines', o.company_id.id, o.partner_id and o.partner_id.id or False)"/> |
||||
|
|
||||
|
</p> |
||||
|
|
||||
|
You should always use t-if since the method returns False if no template is found. |
@ -1,2 +1,3 @@ |
|||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_base_comment_template_user,access_base_comment_template_user,model_base_comment_template,,1,0,0,0 |
||||
access_base_comment_template,access_base_comment_template no one,model_base_comment_template,base.group_no_one,1,1,1,1 |
access_base_comment_template,access_base_comment_template no one,model_base_comment_template,base.group_no_one,1,1,1,1 |
@ -0,0 +1,34 @@ |
|||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# Copyright 2018 ACSONE |
||||
|
# Copyright 2018 Camptocamp |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from odoo import models |
||||
|
|
||||
|
|
||||
|
def setup_test_model(env, model_cls): |
||||
|
"""Pass a test model class and initialize it. |
||||
|
|
||||
|
Courtesy of SBidoul from https://github.com/OCA/mis-builder :) |
||||
|
""" |
||||
|
model_cls._build_model(env.registry, env.cr) |
||||
|
env.registry.setup_models(env.cr) |
||||
|
env.registry.init_models( |
||||
|
env.cr, [model_cls._name], dict(env.context, update_custom_fields=True) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
def teardown_test_model(env, model_cls): |
||||
|
"""Pass a test model class and deinitialize it. |
||||
|
|
||||
|
Courtesy of SBidoul from https://github.com/OCA/mis-builder :) |
||||
|
""" |
||||
|
if not getattr(model_cls, "_teardown_no_delete", False): |
||||
|
del env.registry.models[model_cls._name] |
||||
|
env.registry.setup_models(env.cr) |
||||
|
|
||||
|
|
||||
|
class ResUsers(models.Model): |
||||
|
_name = "res.users" |
||||
|
_inherit = ["res.users", "comment.template"] |
||||
|
_teardown_no_delete = True |
@ -1,37 +1,89 @@ |
|||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). |
|
||||
from odoo.tests.common import TransactionCase |
|
||||
|
# Copyright 2020 NextERP Romania SRL |
||||
|
# Copyright 2021 Tecnativa - Víctor Martínez |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from odoo.tests import common |
||||
|
|
||||
|
from .fake_models import ResUsers, setup_test_model, teardown_test_model |
||||
|
|
||||
class TestResPartner(TransactionCase): |
|
||||
def setUp(self): |
|
||||
super(TestResPartner, self).setUp() |
|
||||
self.template_id = self.env["base.comment.template"].create( |
|
||||
|
|
||||
|
class TestCommentTemplate(common.SavepointCase): |
||||
|
@classmethod |
||||
|
def setUpClass(cls): |
||||
|
super().setUpClass() |
||||
|
setup_test_model(cls.env, ResUsers) |
||||
|
cls.user_obj = cls.env.ref("base.model_res_users") |
||||
|
cls.user = cls.env.ref("base.user_demo") |
||||
|
cls.user2 = cls.env.ref("base.demo_user0") |
||||
|
cls.partner_id = cls.env.ref("base.res_partner_12") |
||||
|
cls.partner2_id = cls.env.ref("base.res_partner_10") |
||||
|
cls.main_company = cls.env.ref("base.main_company") |
||||
|
cls.company = cls.env["res.company"].create({"name": "Test company"}) |
||||
|
cls.before_template_id = cls.env["base.comment.template"].create( |
||||
{ |
{ |
||||
"name": "Comment before lines", |
|
||||
"position": "before_lines", |
|
||||
"text": "<p>Text before lines</p>", |
|
||||
|
"name": "Top template", |
||||
|
"text": "Text before lines", |
||||
|
"model_ids": [(6, 0, cls.user_obj.ids)], |
||||
|
"company_id": cls.company.id, |
||||
} |
} |
||||
) |
) |
||||
|
cls.after_template_id = cls.env["base.comment.template"].create( |
||||
|
{ |
||||
|
"name": "Bottom template", |
||||
|
"position": "after_lines", |
||||
|
"text": "Text after lines", |
||||
|
"model_ids": [(6, 0, cls.user_obj.ids)], |
||||
|
"company_id": cls.company.id, |
||||
|
} |
||||
|
) |
||||
|
cls.user.partner_id.base_comment_template_ids = [ |
||||
|
(4, cls.before_template_id.id), |
||||
|
(4, cls.after_template_id.id), |
||||
|
] |
||||
|
|
||||
def test_commercial_partner_fields(self): |
|
||||
# Azure Interior |
|
||||
partner_id = self.env.ref("base.res_partner_12") |
|
||||
partner_id.property_comment_template_id = self.template_id.id |
|
||||
# Test childs propagation of commercial partner field |
|
||||
for child_id in partner_id.child_ids: |
|
||||
self.assertEqual(child_id.property_comment_template_id, self.template_id) |
|
||||
|
|
||||
def test_get_value_without_partner(self): |
|
||||
self.assertEqual(self.template_id.get_value(), "<p>Text before lines</p>") |
|
||||
|
@classmethod |
||||
|
def tearDownClass(cls): |
||||
|
teardown_test_model(cls.env, ResUsers) |
||||
|
super(TestCommentTemplate, cls).tearDownClass() |
||||
|
|
||||
def test_get_value_with_partner(self): |
|
||||
self.env["res.lang"]._activate_lang("fr_BE") |
|
||||
partner = self.env.ref("base.res_partner_12") |
|
||||
partner.write({"lang": "fr_BE"}) |
|
||||
self.template_id.with_context(lang="fr_BE").write( |
|
||||
{"text": "<p>Testing translated fr_BE</p>"} |
|
||||
|
def test_template_name_get(self): |
||||
|
self.assertEqual( |
||||
|
self.before_template_id.display_name, |
||||
|
"Top template (Top)", |
||||
) |
) |
||||
self.assertEqual( |
self.assertEqual( |
||||
self.template_id.get_value(partner_id=partner.id), |
|
||||
"<p>Testing translated fr_BE</p>", |
|
||||
|
self.after_template_id.display_name, |
||||
|
"Bottom template (Bottom)", |
||||
|
) |
||||
|
|
||||
|
def test_general_template(self): |
||||
|
# Need to force _compute because only trigger when partner_id have changed |
||||
|
self.user._compute_comment_template_ids() |
||||
|
# Check getting default comment template |
||||
|
self.assertTrue(self.before_template_id in self.user.comment_template_ids) |
||||
|
self.assertTrue(self.after_template_id in self.user.comment_template_ids) |
||||
|
|
||||
|
def test_partner_template(self): |
||||
|
self.partner2_id.base_comment_template_ids = [ |
||||
|
(4, self.before_template_id.id), |
||||
|
(4, self.after_template_id.id), |
||||
|
] |
||||
|
self.assertTrue( |
||||
|
self.before_template_id in self.partner2_id.base_comment_template_ids |
||||
|
) |
||||
|
self.assertTrue( |
||||
|
self.after_template_id in self.partner2_id.base_comment_template_ids |
||||
|
) |
||||
|
|
||||
|
def test_partner_template_domain(self): |
||||
|
# Check getting the comment template if domain is set |
||||
|
self.partner2_id.base_comment_template_ids = [ |
||||
|
(4, self.before_template_id.id), |
||||
|
(4, self.after_template_id.id), |
||||
|
] |
||||
|
self.before_template_id.domain = "[('id', 'in', %s)]" % self.user.ids |
||||
|
self.assertTrue( |
||||
|
self.before_template_id in self.partner2_id.base_comment_template_ids |
||||
|
) |
||||
|
self.assertTrue( |
||||
|
self.before_template_id not in self.partner_id.base_comment_template_ids |
||||
) |
) |
@ -0,0 +1,28 @@ |
|||||
|
<odoo> |
||||
|
<record id="view_partner_form" model="ir.ui.view"> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" ref="base.view_partner_form" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<page name='internal_notes' position="after"> |
||||
|
<page name='base_comment_template_ids' string="Comment Templates"> |
||||
|
<field |
||||
|
name="base_comment_template_ids" |
||||
|
nolabel="1" |
||||
|
context="{'comment_template_model_display': True}" |
||||
|
> |
||||
|
<tree> |
||||
|
<field name="display_name" string="Name" /> |
||||
|
<field name="position" /> |
||||
|
<field |
||||
|
name="company_id" |
||||
|
groups="base.group_multi_company" |
||||
|
/> |
||||
|
<field name="model_ids" /> |
||||
|
<field name="domain" /> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</page> |
||||
|
</page> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue