Skip to Content

Add Chatter to Existing Odoo View + Add Tracking on On​e2many Fields

Want to boost visibility and traceability in your Odoo custom models?
January 1, 2025 by
Developerspro
| No comments yet

Here’s how you can add a chatter to an existing form (that doesn’t have one by default), and track changes on a One2many field — perfect for audit logs and traceable workflows!

Step 1: Add Mail Inherit in Python
from odoo import models, fields, api, _
from markupsafe import Markup

class UoMCategoryExt(models.Model):
    _name = 'uom.category'
    _inherit = ['uom.category', 'mail.thread', 'mail.activity.mixin']
    _description = 'Extended UoM Category'
Step 2: Add Chatter in XML View

Just inherit the view and drop this inside your XML:

<record id="view_uom_category_form_inherit" model="ir.ui.view">
    <field name="name">uom.category.form.inherit</field>
    <field name="model">uom.category</field>
    <field name="inherit_id" ref="uom.product_uom_categ_form_view"/>
    <field name="arch" type="xml">
        <xpath expr="//form/sheet" position="after">
            <chatter/>
        </xpath>
    </field>
</record> 

🔹 This injects the chatter panel (mail.thread) into forms where it wasn’t shown before.

Step 3: Track Changes in One2many Field
 Model 1
from odoo import models, fields, api, _
class UoMCategoryExt(models.Model):
    _name = 'uom.category'
    _inherit = ['uom.category', 'mail.thread', 'mail.activity.mixin']
    _description = 'Extended UoM Category'

    uom_ids = fields.One2many('uom.uom', 'category_id') 
Model 2
class UoMExt(models.Model):
    _name = 'uom.uom'
    _inherit = ['uom.uom', 'mail.thread', 'mail.activity.mixin']
    _description = 'Extended UoM'

    category_id = fields.Many2one(
        'uom.category', 'Category', required=True, ondelete='restrict', tracking=True,
        help="Conversion between Units of Measure can only occur if they belong to the same category. The conversion will be made based on the ratios.")
✅ Step 4: Method to Show tracking in chatter
@api.model
def _get_tracked_fields(self):
    """Define which fields to track for custom messages"""
    return ['factor', 'rounding', 'uom_type', 'name', 'category_id']
def write(self, vals):
    old_values = {}
    tracked_fields = self._get_tracked_fields()
    # Store old values before write
    for record in self:
        old_values[record.id] = {}
        for field in tracked_fields:
            if field in vals:
                old_values[record.id][field] = record[field]
    # Perform the write operation
    result = super().write(vals)
    # Process changes for each record
    for record in self:
        if record.id in old_values:
            changes = []
            for field in tracked_fields:
                if field in vals:
                    old_val = old_values[record.id][field]
                    new_val = record[field]

                    # Handle different field types for display
                    if record._fields[field].type == 'many2one':
                        old_val_display = old_val.name if old_val else _("None")
                        new_val_display = new_val.name if new_val else _("None")
                    elif record._fields[field].type == 'selection':
                        selection_dict = dict(record._fields[field].selection)
                        old_val_display = selection_dict.get(old_val, old_val)
                        new_val_display = selection_dict.get(new_val, new_val)
                    else:
                        old_val_display = old_val if old_val is not False else _("None")
                        new_val_display = new_val if new_val is not False else _("None")

                    # Check if value actually changed
                    if old_val != new_val:
                        field_label = record._fields[field].string
                        changes.append((field_label, old_val_display, new_val_display))

            # Create message if there are changes
            if changes:
                # Build simple message
                msg = f"{_('')}"

                for field_label, old_val, new_val in changes:
                    msg += f"• {field_label}: {old_val}   →   {new_val}"
                # Post to category
                record.category_id.message_post(
                    body=f'{record._description}: {record.display_name} {msg}',
                    subtype_xmlid='mail.mt_comment'
                )

    return result

This gives you a clean change history, even for complex relational fields.


💡 Visit Developerspro for more real-world Odoo Dev Tips. Let us know in the comments!

Developerspro January 1, 2025
Share this post
Archive
Sign in to leave a comment