tracking_manager: refactor code, remove tracking_model
- remove tracking_model (less model, less code, less issue) - add automatic rule for default config (this avoid missing tracked field after module installation)pull/2916/head
parent
56312632a0
commit
be22968e91
|
@ -10,7 +10,7 @@
|
|||
"category": "Tools",
|
||||
"website": "https://github.com/OCA/server-tools",
|
||||
"author": "Akretion, Odoo Community Association (OCA)",
|
||||
"maintainers": ["Kev-Roche"],
|
||||
"maintainers": ["Kev-Roche", "sebastienbeau"],
|
||||
"license": "AGPL-3",
|
||||
"application": False,
|
||||
"installable": True,
|
||||
|
@ -19,9 +19,8 @@
|
|||
"mail",
|
||||
],
|
||||
"data": [
|
||||
"views/ir_model.xml",
|
||||
"views/ir_model_fields.xml",
|
||||
"views/ir_model.xml",
|
||||
"views/message_template.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
from . import mail_thread
|
||||
from . import tracking_model
|
||||
from . import ir_model
|
||||
|
|
|
@ -2,116 +2,129 @@
|
|||
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from ast import literal_eval
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class IrModel(models.Model):
|
||||
_inherit = "ir.model"
|
||||
|
||||
o2m_model_ids = fields.One2many(
|
||||
string="One2many Models",
|
||||
comodel_name="ir.model",
|
||||
compute="_compute_o2m_model_ids",
|
||||
readonly=True,
|
||||
)
|
||||
custom_tracking_field_ids = fields.One2many(
|
||||
comodel_name="tracking.model.field",
|
||||
inverse_name="model_id",
|
||||
string="Custom Tracked Fields",
|
||||
compute="_compute_custom_tracking_fields",
|
||||
active_custom_tracking = fields.Boolean(default=False)
|
||||
tracked_field_count = fields.Integer(compute="_compute_tracked_field_count")
|
||||
automatic_custom_tracking = fields.Boolean(
|
||||
compute="_compute_automatic_custom_tracking",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
field_count = fields.Integer(compute="_compute_tracked_field_count")
|
||||
apply_custom_tracking = fields.Boolean(
|
||||
"Apply custom tracking on fields",
|
||||
default=False,
|
||||
help="""Add tracking on all this model fields if they
|
||||
are not readonly True, neither computed.""",
|
||||
help=("If tick new field will be automatically tracked " "if the domain match"),
|
||||
)
|
||||
automatic_custom_tracking_domain = fields.Char(
|
||||
compute="_compute_automatic_custom_tracking_domain",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.depends("field_id", "apply_custom_tracking")
|
||||
def _compute_custom_tracking_fields(self):
|
||||
for rec in self:
|
||||
fields = rec.env["ir.model.fields"].search(
|
||||
[("model_id.model", "=", rec.model)]
|
||||
@api.depends("active_custom_tracking")
|
||||
def _compute_automatic_custom_tracking(self):
|
||||
for record in self:
|
||||
record.automatic_custom_tracking = False
|
||||
|
||||
def _default_automatic_custom_tracking_domain_rules(self):
|
||||
return {
|
||||
"product.product": [
|
||||
"|",
|
||||
("ttype", "!=", "one2many"),
|
||||
("name", "in", ["barcode_ids"]),
|
||||
],
|
||||
"sale.order": [
|
||||
"|",
|
||||
("ttype", "!=", "one2many"),
|
||||
("name", "in", ["line_ids"]),
|
||||
],
|
||||
"account.move": [
|
||||
"|",
|
||||
("ttype", "!=", "one2many"),
|
||||
("name", "in", ["invoice_line_ids"]),
|
||||
],
|
||||
"default_automatic_rule": [("ttype", "!=", "one2many")],
|
||||
}
|
||||
|
||||
@api.depends("automatic_custom_tracking")
|
||||
def _compute_automatic_custom_tracking_domain(self):
|
||||
rules = self._default_automatic_custom_tracking_domain_rules()
|
||||
for record in self:
|
||||
record.automatic_custom_tracking_domain = str(
|
||||
rules.get(record.model) or rules.get("default_automatic_rule")
|
||||
)
|
||||
fields_ids = []
|
||||
for field in fields:
|
||||
values = {}
|
||||
values["tracking_field_id"] = field.id
|
||||
values["model_id"] = rec.id
|
||||
fields_ids.append((0, 0, values))
|
||||
rec.custom_tracking_field_ids = [(6, 0, [])]
|
||||
rec.custom_tracking_field_ids = fields_ids
|
||||
|
||||
@api.depends("field_id", "apply_custom_tracking")
|
||||
def _compute_o2m_model_ids(self):
|
||||
for rec in self:
|
||||
o2m_model_list = []
|
||||
if rec.apply_custom_tracking:
|
||||
for field in rec.field_id:
|
||||
if field.ttype == "one2many":
|
||||
o2m_relation_id = self.search(
|
||||
[("model", "=", field.relation)], limit=1
|
||||
)
|
||||
o2m_model_list.append(o2m_relation_id.id)
|
||||
rec.o2m_model_ids = [(6, 0, o2m_model_list)]
|
||||
def update_custom_tracking(self):
|
||||
for record in self:
|
||||
fields = record.field_id.filtered("trackable").filtered_domain(
|
||||
literal_eval(record.automatic_custom_tracking_domain)
|
||||
)
|
||||
fields.write({"custom_tracking": True})
|
||||
untrack_fields = record.field_id - fields
|
||||
untrack_fields.write({"custom_tracking": False})
|
||||
|
||||
@api.depends(
|
||||
"custom_tracking_field_ids", "custom_tracking_field_ids.custom_tracking"
|
||||
)
|
||||
@api.depends("field_id.custom_tracking")
|
||||
def _compute_tracked_field_count(self):
|
||||
for rec in self:
|
||||
rec.field_count = sum(
|
||||
rec.custom_tracking_field_ids.mapped("custom_tracking")
|
||||
)
|
||||
|
||||
def show_custom_tracked_field(self):
|
||||
return {
|
||||
"name": "Custom tracked fields",
|
||||
"type": "ir.actions.act_window",
|
||||
"res_id": self.id,
|
||||
"view_mode": "tree",
|
||||
"res_model": "tracking.model.field",
|
||||
"view_id": self.env.ref(
|
||||
"tracking_manager.custom_tracking_field_view_tree"
|
||||
).id,
|
||||
"target": "current",
|
||||
"domain": [("id", "in", self.custom_tracking_field_ids.ids)],
|
||||
}
|
||||
|
||||
def show_o2m_models(self):
|
||||
return {
|
||||
"name": "o2m models",
|
||||
"type": "ir.actions.act_window",
|
||||
"res_id": self.id,
|
||||
"view_mode": "tree,form",
|
||||
"res_model": "ir.model",
|
||||
"views": [
|
||||
(self.env.ref("base.view_model_tree").id, "tree"),
|
||||
(self.env.ref("base.view_model_form").id, "form"),
|
||||
],
|
||||
"target": "current",
|
||||
"domain": [("id", "in", self.o2m_model_ids.ids)],
|
||||
}
|
||||
rec.tracked_field_count = len(rec.field_id.filtered("custom_tracking"))
|
||||
|
||||
|
||||
class IrModelFields(models.Model):
|
||||
_inherit = "ir.model.fields"
|
||||
|
||||
custom_tracking_id = fields.Many2one(
|
||||
comodel_name="tracking.model.field",
|
||||
string="Technical Custom Tracking Field",
|
||||
compute="_compute_custom_tracking_field_id",
|
||||
custom_tracking = fields.Boolean(
|
||||
compute="_compute_custom_tracking",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
native_tracking = fields.Boolean(
|
||||
compute="_compute_native_tracking",
|
||||
store=True,
|
||||
)
|
||||
trackable = fields.Boolean(
|
||||
compute="_compute_trackable",
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends("model_id.apply_custom_tracking")
|
||||
def _compute_custom_tracking_field_id(self):
|
||||
for rec in self:
|
||||
if rec.model_id.apply_custom_tracking:
|
||||
rec.custom_tracking_id = self.env["tracking.model.field"].search(
|
||||
[("tracking_field_id", "=", rec.id), ("model_id", "=", rec._name)],
|
||||
limit=1,
|
||||
)
|
||||
@api.depends("native_tracking")
|
||||
def _compute_custom_tracking(self):
|
||||
for record in self:
|
||||
if record.model_id.automatic_custom_tracking:
|
||||
domain = literal_eval(record.model_id.automatic_custom_tracking_domain)
|
||||
record.custom_tracking = bool(record.filtered_domain(domain))
|
||||
else:
|
||||
rec.custom_tracking_id = False
|
||||
record.custom_tracking = record.native_tracking
|
||||
|
||||
@api.depends("tracking")
|
||||
def _compute_native_tracking(self):
|
||||
for record in self:
|
||||
record.native_tracking = bool(record.tracking)
|
||||
|
||||
@api.depends("readonly", "related", "store")
|
||||
def _compute_trackable(self):
|
||||
blacklists = [
|
||||
"activity_ids",
|
||||
"message_ids",
|
||||
"message_last_post",
|
||||
"message_main_attachment",
|
||||
]
|
||||
for rec in self:
|
||||
rec.trackable = (
|
||||
rec.name not in blacklists
|
||||
and rec.store
|
||||
and not rec.readonly
|
||||
and not rec.related
|
||||
)
|
||||
|
||||
def write(self, vals):
|
||||
custom_tracking = None
|
||||
if "custom_tracking" in vals:
|
||||
self.check_access_rights("write")
|
||||
custom_tracking = vals.pop("custom_tracking")
|
||||
self._write({"custom_tracking": custom_tracking})
|
||||
self.invalidate_cache(["custom_tracking"])
|
||||
return super().write(vals)
|
||||
|
|
|
@ -8,6 +8,7 @@ from odoo import models, tools
|
|||
class MailThread(models.AbstractModel):
|
||||
_inherit = "mail.thread"
|
||||
|
||||
# TODO invalidate ormcache
|
||||
@tools.ormcache("self.env.uid", "self.env.su")
|
||||
def _get_tracked_fields(self):
|
||||
res = super()._get_tracked_fields()
|
||||
|
@ -21,12 +22,12 @@ class MailThread(models.AbstractModel):
|
|||
self.env["ir.model"]
|
||||
.sudo()
|
||||
.search(
|
||||
[("model", "=", self._name), ("apply_custom_tracking", "=", True)],
|
||||
[("model", "=", self._name), ("active_custom_tracking", "=", True)],
|
||||
limit=1,
|
||||
)
|
||||
)
|
||||
if tracking_model:
|
||||
track_fields = tracking_model.custom_tracking_field_ids.filtered(
|
||||
track_fields = tracking_model.field_id.filtered(
|
||||
lambda f: f.custom_tracking
|
||||
).mapped("name")
|
||||
return track_fields and set(self.fields_get(track_fields))
|
||||
|
@ -112,8 +113,8 @@ class MailThread(models.AbstractModel):
|
|||
# tracking (apply_custom_tracking = True), we track
|
||||
# the changes only for fields with custom_tracking.
|
||||
if (
|
||||
line_model_id.apply_custom_tracking
|
||||
and not line_field_id.custom_tracking_id.custom_tracking
|
||||
line_model_id.active_custom_tracking
|
||||
and not line_field_id.custom_tracking
|
||||
):
|
||||
old = new = False
|
||||
elif line_field_id.ttype in ["one2many", "many2one", "many2many"]:
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
# Copyright (C) 2022 Akretion (<http://www.akretion.com>).
|
||||
# @author Kévin Roche <kevin.roche@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class TrackingModelField(models.Model):
|
||||
_name = "tracking.model.field"
|
||||
_description = "Tracking Model Field"
|
||||
|
||||
name = fields.Char(related="tracking_field_id.name")
|
||||
tracking_field_id = fields.Many2one(
|
||||
"ir.model.fields",
|
||||
"Field",
|
||||
)
|
||||
model_id = fields.Many2one(
|
||||
comodel_name="ir.model",
|
||||
string="Tracking Model Field",
|
||||
)
|
||||
custom_tracking = fields.Boolean(
|
||||
string="Custom Tracking",
|
||||
compute="_compute_custom_tracking",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
native_tracking_field = fields.Integer(
|
||||
string="Native Tracking", related="tracking_field_id.tracking"
|
||||
)
|
||||
type_field = fields.Selection(
|
||||
string="Kind Field", related="tracking_field_id.ttype"
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"tracking_field_id",
|
||||
"tracking_field_id.readonly",
|
||||
"tracking_field_id.related",
|
||||
"tracking_field_id.store",
|
||||
)
|
||||
def _compute_custom_tracking(self):
|
||||
# No tracking on compute / readonly fields
|
||||
# Custom tracking include native tracking attribute.
|
||||
for rec in self:
|
||||
field_id = rec.tracking_field_id
|
||||
if (
|
||||
field_id.readonly
|
||||
or field_id.related
|
||||
or (field_id.compute and field_id.store and not field_id.readonly)
|
||||
) and not field_id.tracking:
|
||||
rec.custom_tracking = False
|
||||
else:
|
||||
rec.custom_tracking = True
|
|
@ -1 +1,2 @@
|
|||
* Kévin Roche <kevin.roche@akretion.com>
|
||||
* Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_custom_tracking_model_field,tracking.model.field.user,model_tracking_model_field,base.group_user,1,1,1,1
|
|
|
@ -28,35 +28,40 @@ class TestTrackingManager(SavepointCase):
|
|||
}
|
||||
)
|
||||
|
||||
def test_1_ir_model_config(self):
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
# custom_tracking_field_ids
|
||||
self.assertEqual(
|
||||
len(self.partner_model.field_id),
|
||||
len(self.partner_model.custom_tracking_field_ids),
|
||||
)
|
||||
# o2m_model_ids
|
||||
self.assertEqual(
|
||||
len(self.partner_model.o2m_model_ids),
|
||||
len(self.partner_model.field_id.filtered(lambda x: x.ttype == "one2many")),
|
||||
def _active_tracking(self, fields_list):
|
||||
self.partner_model.active_custom_tracking = True
|
||||
for field in self._get_fields(fields_list):
|
||||
field.custom_tracking = True
|
||||
|
||||
def _get_fields(self, fields_list):
|
||||
return self.env["ir.model.fields"].search(
|
||||
[
|
||||
("model_id.model", "=", "res.partner"),
|
||||
("name", "in", fields_list),
|
||||
]
|
||||
)
|
||||
|
||||
def test_2_tracking_model_field_config(self):
|
||||
self.partner_2 = self.env.ref("base.res_partner_2")
|
||||
self.partner_1_w_parent = self.env.ref("base.res_partner_address_1")
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
# Readonly, related are not tracked
|
||||
parent_name = self.partner_model.custom_tracking_field_ids.filtered(
|
||||
lambda x: x.name == "parent_name"
|
||||
)
|
||||
self.assertFalse(parent_name.custom_tracking)
|
||||
# Other fields are tracked
|
||||
street = self.partner_model.custom_tracking_field_ids.filtered(
|
||||
lambda x: x.name == "street"
|
||||
)
|
||||
self.assertTrue(street.custom_tracking)
|
||||
def test_not_tracked(self):
|
||||
self.partner_model.active_custom_tracking = True
|
||||
field = self._get_fields(["category_id"])[0]
|
||||
self.assertFalse(field.native_tracking)
|
||||
self.assertFalse(field.custom_tracking)
|
||||
|
||||
def test_3_m2m_add_line(self):
|
||||
def test_native_tracked(self):
|
||||
self.partner_model.active_custom_tracking = True
|
||||
field = self._get_fields(["email"])[0]
|
||||
self.assertTrue(field.native_tracking)
|
||||
self.assertTrue(field.custom_tracking)
|
||||
|
||||
def test_update_tracked(self):
|
||||
self.partner_model.active_custom_tracking = True
|
||||
field = self._get_fields(["category_id"])[0]
|
||||
self.assertFalse(field.native_tracking)
|
||||
self.partner_model.automatic_custom_tracking = True
|
||||
self.partner_model.update_custom_tracking()
|
||||
self.assertTrue(field.custom_tracking)
|
||||
|
||||
def test_m2m_add_line(self):
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_1.category_id = [
|
||||
(4, self.env.ref("base.res_partner_category_3").id)
|
||||
|
@ -64,7 +69,7 @@ class TestTrackingManager(SavepointCase):
|
|||
after_msg = self.partner_1.message_ids
|
||||
self.assertEqual(len(initial_msg), len(after_msg))
|
||||
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["category_id"])
|
||||
self.partner_1.category_id = [
|
||||
(4, self.env.ref("base.res_partner_category_8").id)
|
||||
]
|
||||
|
@ -72,21 +77,21 @@ class TestTrackingManager(SavepointCase):
|
|||
self.assertEqual(len(initial_msg) + 1, len(after_msg))
|
||||
self.assertTrue("New" in after_msg[0].body)
|
||||
|
||||
def test_4_m2m_delete_line(self):
|
||||
def test_m2m_delete_line(self):
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_1.category_id = [(3, self.partner_1.category_id[0].id)]
|
||||
after_msg = self.partner_1.message_ids
|
||||
self.assertEqual(len(initial_msg), len(after_msg))
|
||||
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["category_id"])
|
||||
self.partner_1.category_id = [(3, self.partner_1.category_id[0].id)]
|
||||
after_msg = self.partner_1.message_ids
|
||||
self.assertEqual(len(initial_msg) + 1, len(after_msg))
|
||||
self.assertTrue("Delete" in after_msg[0].body)
|
||||
|
||||
def test_5_m2m_multi_line(self):
|
||||
def test_m2m_multi_line(self):
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["category_id"])
|
||||
self.partner_1.category_id = [
|
||||
(3, self.partner_1.category_id[0].id),
|
||||
(4, self.env.ref("base.res_partner_category_8").id),
|
||||
|
@ -97,26 +102,26 @@ class TestTrackingManager(SavepointCase):
|
|||
self.assertEqual(after_msg[0].body.count("New"), 2)
|
||||
self.assertEqual(after_msg[0].body.count("Delete"), 1)
|
||||
|
||||
def test_6_o2m_add(self):
|
||||
def test_o2m_add(self):
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["bank_ids"])
|
||||
self.partner_1.bank_ids = [(4, self.bank_partner_2.id)]
|
||||
after_msg = self.partner_1.message_ids
|
||||
self.assertEqual(len(initial_msg) + 1, len(after_msg))
|
||||
self.assertTrue("New" in after_msg[0].body)
|
||||
|
||||
def test_7_o2m_delete(self):
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
def test_o2m_delete(self):
|
||||
self._active_tracking(["bank_ids"])
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_1.write({"bank_ids": [(3, self.partner_1.bank_ids[0].id)]})
|
||||
after_msg = self.partner_1.message_ids
|
||||
self.assertEqual(len(initial_msg) + 1, len(after_msg))
|
||||
self.assertTrue("Delete" in after_msg[0].body)
|
||||
|
||||
def test_8_o2m_change_in_line(self):
|
||||
def test_o2m_change_in_line(self):
|
||||
self.partner_1.bank_ids = [(6, 0, self.bank_partner_2.id)]
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["bank_ids"])
|
||||
self.partner_1.write(
|
||||
{
|
||||
"bank_ids": [(1, self.partner_1.bank_ids.id, {"acc_number": "123"})],
|
||||
|
@ -129,10 +134,8 @@ class TestTrackingManager(SavepointCase):
|
|||
bank_model = self.env["ir.model"].search(
|
||||
[("model", "=", self.bank_partner_2._name)], limit=1
|
||||
)
|
||||
bank_model.apply_custom_tracking = True
|
||||
acc_number = bank_model.custom_tracking_field_ids.filtered(
|
||||
lambda x: x.name == "acc_number"
|
||||
)
|
||||
bank_model.active_custom_tracking = True
|
||||
acc_number = bank_model.field_id.filtered(lambda x: x.name == "acc_number")
|
||||
acc_number.custom_tracking = False
|
||||
self.partner_1.write(
|
||||
{
|
||||
|
@ -142,9 +145,9 @@ class TestTrackingManager(SavepointCase):
|
|||
after_msg_2 = self.partner_1.message_ids
|
||||
self.assertEqual(len(after_msg), len(after_msg_2))
|
||||
|
||||
def test_9_o2m_multi_line(self):
|
||||
def test_o2m_multi_line(self):
|
||||
initial_msg = self.partner_1.message_ids
|
||||
self.partner_model.apply_custom_tracking = True
|
||||
self._active_tracking(["bank_ids"])
|
||||
self.partner_1.bank_ids = [
|
||||
(3, self.partner_1.bank_ids[0].id),
|
||||
(4, self.bank_partner_2.id),
|
||||
|
|
|
@ -10,40 +10,50 @@
|
|||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet/group[1]" position="after">
|
||||
|
||||
<group string="Tracking">
|
||||
<group>
|
||||
<field name="apply_custom_tracking" />
|
||||
<button
|
||||
name="show_custom_tracked_field"
|
||||
string="Custom Tracked fields"
|
||||
<group string="Custom Tracking">
|
||||
<group>
|
||||
<field name="active_custom_tracking" string="Active" />
|
||||
<field
|
||||
name="automatic_custom_tracking"
|
||||
string="Automatic configuration"
|
||||
attrs="{'invisible': [('active_custom_tracking', '=', False)]}"
|
||||
/>
|
||||
<field
|
||||
name="automatic_custom_tracking_domain"
|
||||
string="Domain"
|
||||
attrs="{
|
||||
'invisible': [('automatic_custom_tracking', '=', False)],
|
||||
'required': [('automatic_custom_tracking', '=', True)],
|
||||
}"
|
||||
/>
|
||||
<label
|
||||
for="update_custom_tracking"
|
||||
string="Update fields configuration"
|
||||
attrs="{'invisible': [('automatic_custom_tracking', '=', False)]}"
|
||||
/>
|
||||
<button
|
||||
name="update_custom_tracking"
|
||||
string="Update"
|
||||
icon="fa-refresh"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
attrs="{'invisible': [('apply_custom_tracking', '=', False)]}"
|
||||
attrs="{'invisible': [('automatic_custom_tracking', '=', False)]}"
|
||||
/>
|
||||
<button
|
||||
name="show_o2m_models"
|
||||
string="One2many related models"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
attrs="{'invisible': [('apply_custom_tracking', '=', False)]}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet/group[1]" position="before">
|
||||
<div
|
||||
class="oe_button_box"
|
||||
name="button_box"
|
||||
attrs="{'invisible': [('apply_custom_tracking', '=', False)]}"
|
||||
>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button
|
||||
name="show_custom_tracked_field"
|
||||
type="object"
|
||||
name="%(ir_model_fields_action)d"
|
||||
type="action"
|
||||
class="oe_stat_button"
|
||||
icon="fa-server"
|
||||
attrs="{'invisible': [('active_custom_tracking', '=', False)]}"
|
||||
>
|
||||
<field
|
||||
name="field_count"
|
||||
name="tracked_field_count"
|
||||
widget="statinfo"
|
||||
string="Tracked Fields"
|
||||
/>
|
||||
|
@ -53,15 +63,4 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="custom_tracking_view_tree" model="ir.ui.view">
|
||||
<field name="model">ir.model</field>
|
||||
<field name="name">tracking.ir.model.tree</field>
|
||||
<field name="inherit_id" ref="base.view_model_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree/field[@name='transient']" position="after">
|
||||
<field name="apply_custom_tracking" readonly="True" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -3,17 +3,37 @@
|
|||
@author Kévin Roche <kevin.roche@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="custom_tracking_field_view_tree" model="ir.ui.view">
|
||||
<field name="model">tracking.model.field</field>
|
||||
<field name="name">tracking.model.field.tree</field>
|
||||
|
||||
<record model="ir.actions.act_window" id="ir_model_fields_action">
|
||||
<field name="name">Trackable Fields</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">ir.model.fields</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field
|
||||
name="domain"
|
||||
>[("trackable", "=", True), ("model_id", "=", context['active_id'])]</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="target">current</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_model_fields_view_tree_custom_tracking" model="ir.ui.view">
|
||||
<field name="model">ir.model.fields</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom" create="false">
|
||||
<tree editable="bottom" create="0" delete="0" duplicate="0">
|
||||
<field name="name" readonly="True" />
|
||||
<field name="field_description" readonly="True" />
|
||||
<field name="ttype" readonly="True" />
|
||||
<field name="native_tracking" readonly="True" />
|
||||
<field name="custom_tracking" widget="boolean_toggle" />
|
||||
<field name="native_tracking_field" readonly="True" />
|
||||
<field name="type_field" readonly="True" />
|
||||
<field name="model_id" readonly="True" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_model_fields_action_view" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2" />
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="ir_model_fields_view_tree_custom_tracking" />
|
||||
<field name="act_window_id" ref="ir_model_fields_action" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
Loading…
Reference in New Issue