What Are Activities in Odoo?
Activities are actionable to-do items attached to records. Unlike chatter messages, activities have a deadline, an assigned user, and a type. They appear in the chatter, on the activity view, and in the systray menu. Any model that inherits mail.activity.mixin supports activities.
class CustomModel(models.Model):
_name = 'custom.model'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Custom Model with Activities'Built-In Activity Types
| XML ID | Name | Icon |
|---|---|---|
| mail.mail_activity_data_email | fa-envelope | |
| mail.mail_activity_data_call | Call | fa-phone |
| mail.mail_activity_data_meeting | Meeting | fa-users |
| mail.mail_activity_data_todo | To-Do | fa-tasks |
| mail.mail_activity_data_upload_document | Upload Document | fa-upload |
Creating Custom Activity Types
<record id="activity_type_review" model="mail.activity.type">
<field name="name">Review Required</field>
<field name="summary">Review and approve this document</field>
<field name="res_model_id" ref="model_sale_order"/>
<field name="delay_count">2</field>
<field name="delay_unit">days</field>
<field name="delay_from">current_date</field>
<field name="icon">fa-check-circle</field>
<field name="default_user_id" ref="base.user_admin"/>
<field name="chaining_type">trigger</field>
<field name="triggered_next_type_id" ref="mail.mail_activity_data_email"/>
</record>Activity type fields:
- delay_count: Default deadline offset
- delay_unit: days, weeks, or months
- delay_from: current_date or previous_activity_type_id
- chaining_type: suggest (recommend next) or trigger (auto-create next)
- triggered_next_type_id: Activity type to create when this one is completed
Scheduling Activities Programmatically
Basic Scheduling
record.activity_schedule(
'mail.mail_activity_data_call',
date_deadline=fields.Date.today() + timedelta(days=3),
summary='Follow up with customer',
note='Discuss pricing and delivery schedule.',
user_id=salesperson.id,
)Schedule for Multiple Records
# Schedule same activity for all records in recordset
records.activity_schedule(
'mail.mail_activity_data_todo',
date_deadline=fields.Date.today() + timedelta(days=7),
summary='Review pending items',
user_id=manager.id,
)Schedule with Custom Activity Type
record.activity_schedule(
'my_module.activity_type_review',
summary='Review and approve this quotation',
note=f'Quotation amount: {record.amount_total:,.2f}',
user_id=record.user_id.id,
)Completing Activities
# Mark activity as done with feedback
record.activity_feedback(
['mail.mail_activity_data_call'],
feedback='Customer confirmed the order. Proceed with delivery.',
)
# Mark all activities of a type as done
record.activity_feedback(
['mail.mail_activity_data_todo'],
feedback='All items reviewed.',
)
# Cancel/unlink activities without feedback
record.activity_unlink(['mail.mail_activity_data_call'])Activity-Driven Workflow
Use activity chaining to create multi-step workflows:
# Step 1: Review (auto-triggers Step 2 when done)
<record id="activity_step1_review" model="mail.activity.type">
<field name="name">Step 1: Review</field>
<field name="chaining_type">trigger</field>
<field name="triggered_next_type_id" ref="activity_step2_approve"/>
</record>
# Step 2: Approve (suggests Step 3)
<record id="activity_step2_approve" model="mail.activity.type">
<field name="name">Step 2: Approve</field>
<field name="chaining_type">suggest</field>
<field name="suggest_next_action_id" ref="activity_step3_execute"/>
</record>
# Step 3: Execute
<record id="activity_step3_execute" model="mail.activity.type">
<field name="name">Step 3: Execute</field>
</record>Querying Activities
# Find overdue activities
overdue = self.env['mail.activity'].search([
('date_deadline', '<', fields.Date.today()),
('user_id', '=', self.env.uid),
])
# Find records with pending activities
records_with_activities = self.env['sale.order'].search([
('activity_ids', '!=', False),
('activity_ids.date_deadline', '<=', fields.Date.today()),
])
# Count activities by type
activities = self.env['mail.activity'].read_group(
[('user_id', '=', self.env.uid)],
['activity_type_id'],
['activity_type_id']
)Automated Activity Scheduling
Schedule activities automatically on record events:
class SaleOrder(models.Model):
_inherit = 'sale.order'
def action_confirm(self):
res = super().action_confirm()
# Schedule delivery follow-up after confirmation
for order in self:
order.activity_schedule(
'mail.mail_activity_data_todo',
date_deadline=fields.Date.today() + timedelta(days=14),
summary='Confirm delivery completed',
user_id=order.user_id.id,
)
return res
def write(self, vals):
res = super().write(vals)
# Schedule review when amount changes significantly
if 'amount_total' in vals:
for order in self:
if order.amount_total > 50000:
order.activity_schedule(
'my_module.activity_type_review',
summary='High-value order review',
user_id=order.team_id.user_id.id or order.user_id.id,
)
return resActivity View
Odoo provides a dedicated activity view for managing all activities on a model:
<record id="action_sale_order_activities" model="ir.actions.act_window">
<field name="name">Sales Activities</field>
<field name="res_model">sale.order</field>
<field name="view_mode">activity,tree,form</field>
</record>Best Practices
- Use meaningful activity types — do not use generic "To-Do" for everything
- Set realistic deadlines — activities with past deadlines appear as overdue in the systray
- Assign to the right user — unassigned activities are easily missed
- Use chaining for multi-step approvals instead of scheduling all steps upfront
- Clean up completed activities — they stay in the database unless explicitly unlinked
- Include context in the note field so the assignee knows what to do