Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions automation_oca_activity_note_template/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
=======================================
Automation OCA - Activity Note Template
=======================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:6fac894cded1581e6da7ead1f6d5abe64054691afb727804263b27cb47eb0bff
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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%2Fautomation-lightgray.png?logo=github
:target: https://github.com/OCA/automation/tree/18.0/automation_oca_activity_note_template
:alt: OCA/automation
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/automation-18-0/automation-18-0-automation_oca_activity_note_template
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/automation&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module extends the **Activity** step type in ``automation_oca``
with the ability to select a **mail template** as the source for the
activity's summary and note.

When a mail template is selected on an automation step:

- The template **subject** is rendered and used as the **activity
summary**.
- The template **body** is rendered and used as the **activity note**.

Both fields are rendered using the ``inline_template`` engine, which
supports ``{{ object.field }}`` and ``{{ object.method() }}``
expressions evaluated against the target record at the moment the
activity is created.

This makes it straightforward to generate **dynamic, personalised
activity notes** by calling a method on the target model from inside the
template body.

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

``automation_oca`` activity steps support a static **Note** and
**Summary** field, which are written as plain text or HTML at
configuration time and copied verbatim to every activity created by the
step.

This is limiting when the note needs to reflect data specific to each
record — for example, a personalised LinkedIn outreach prompt.

``automation_oca_activity_note_template`` solves this by delegating the
rendering to a **mail template**, which already has a well-established
mechanism for per-record dynamic content and is familiar to Odoo users.

Usage
=====

Configure a mail template
-------------------------

1. Go to **Email** → **Templates** and create a new template.

2. Set the **Applies To** model to match the model used in your
automation (e.g. *Contact*, *CRM Lead*).

3. Write the **Subject** — it will become the **activity summary**. Use
``{{ object.field }}`` expressions to include record-specific data.

4. Write the **Body** — it will become the **activity note**. You may
call methods on ``object``, for example:

::

{{ object.generate_note() }}

Configure the automation step
-----------------------------

1. Open an **Automation Configuration** and add or edit an **Activity**
step.
2. In the **Activity** tab, select the template in the **Note Template**
field.
3. The static **Summary** and **Note** fields are hidden when a template
is selected, as they are replaced by the rendered template output.
4. Save and start the automation as usual.

When the step runs, the template subject and body are rendered
individually for each target record and set as the activity summary and
note respectively.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/automation/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/automation/issues/new?body=module:%20automation_oca_activity_note_template%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* ForgeFlow

Contributors
------------

- Jordi Ballester (`ForgeFlow <https://www.forgeflow.com/>`__)

Other credits
-------------

The development of this module has been financially supported by:

- `ForgeFlow <https://www.forgeflow.com/>`__

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/automation <https://github.com/OCA/automation/tree/18.0/automation_oca_activity_note_template>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions automation_oca_activity_note_template/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright 2026 ForgeFlow
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import models
15 changes: 15 additions & 0 deletions automation_oca_activity_note_template/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2026 ForgeFlow
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Automation OCA - Activity Note Template",
"summary": "Render activity notes from a mail template in automation steps",
"version": "18.0.1.0.0",
"category": "Technical",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"license": "AGPL-3",
"depends": ["automation_oca"],
"data": [
"views/automation_configuration_step_views.xml",
],
"installable": True,
}
4 changes: 4 additions & 0 deletions automation_oca_activity_note_template/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 ForgeFlow
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import automation_configuration_step
from . import automation_record_step
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2026 ForgeFlow
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models


class AutomationConfigurationStep(models.Model):
_inherit = "automation.configuration.step"

activity_note_template_id = fields.Many2one(
"mail.template",
string="Note Template",
domain="[('model_id', '=', model_id)]",
help="If set, the activity note is rendered from this mail template. "
"The template body may use {{ object.method() }} expressions. "
"Overrides the static Note field.",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2026 ForgeFlow
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from dateutil.relativedelta import relativedelta

from odoo import fields, models


class AutomationRecordStep(models.Model):
_inherit = "automation.record.step"

def _render_template_for_record(self, template_src, res_id, engine="inline_template"):
rendered = self.env["mail.template"]._render_template(
template_src,
self.record_id.model,
[res_id],
engine=engine,
)
return rendered.get(res_id, "")

def _get_activity_summary(self):
template = self.configuration_step_id.activity_note_template_id
if not template:
return self.configuration_step_id.activity_summary or ""
return self._render_template_for_record(template.subject, self.record_id.res_id)

def _get_activity_note(self):
template = self.configuration_step_id.activity_note_template_id
if not template:
return self.configuration_step_id.activity_note or ""
return self._render_template_for_record(template.body_html, self.record_id.res_id)

def _run_activity(self):
if not self.configuration_step_id.activity_note_template_id:
return super()._run_activity()

record = self.env[self.record_id.model].browse(self.record_id.res_id)
step = self.configuration_step_id
vals = {
"summary": self._get_activity_summary(),
"note": self._get_activity_note(),
"activity_type_id": step.activity_type_id.id,
"automation_record_step_id": self.id,
}
if step.activity_date_deadline_range > 0:
range_type = step.activity_date_deadline_range_type
vals["date_deadline"] = fields.Date.context_today(self) + relativedelta(
**{range_type: step.activity_date_deadline_range}
)
user = False
if step.activity_user_type == "specific":
user = step.activity_user_id
elif step.activity_user_type == "generic":
user = record[step.activity_user_field_id.name]
if user:
vals["user_id"] = user.id
record.activity_schedule(**vals)
return True
3 changes: 3 additions & 0 deletions automation_oca_activity_note_template/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
10 changes: 10 additions & 0 deletions automation_oca_activity_note_template/readme/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
`automation_oca` activity steps support a static **Note** and **Summary** field,
which are written as plain text or HTML at configuration time and copied verbatim
to every activity created by the step.

This is limiting when the note needs to reflect data specific to each record —
for example, a personalised LinkedIn outreach prompt.

`automation_oca_activity_note_template` solves this by delegating the rendering
to a **mail template**, which already has a well-established mechanism for
per-record dynamic content and is familiar to Odoo users.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Jordi Ballester ([ForgeFlow](https://www.forgeflow.com/))
3 changes: 3 additions & 0 deletions automation_oca_activity_note_template/readme/CREDITS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The development of this module has been financially supported by:

- [ForgeFlow](https://www.forgeflow.com/)
14 changes: 14 additions & 0 deletions automation_oca_activity_note_template/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
This module extends the **Activity** step type in `automation_oca` with the ability
to select a **mail template** as the source for the activity's summary and note.

When a mail template is selected on an automation step:

- The template **subject** is rendered and used as the **activity summary**.
- The template **body** is rendered and used as the **activity note**.

Both fields are rendered using the `inline_template` engine, which supports
`{{ object.field }}` and `{{ object.method() }}` expressions evaluated against
the target record at the moment the activity is created.

This makes it straightforward to generate **dynamic, personalised activity notes**
by calling a method on the target model from inside the template body.
26 changes: 26 additions & 0 deletions automation_oca_activity_note_template/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Configure a mail template
--------------------------

1. Go to **Email** → **Templates** and create a new template.
2. Set the **Applies To** model to match the model used in your automation
(e.g. *Contact*, *CRM Lead*).
3. Write the **Subject** — it will become the **activity summary**.
Use `{{ object.field }}` expressions to include record-specific data.
4. Write the **Body** — it will become the **activity note**.
You may call methods on `object`, for example:

```
{{ object.generate_note() }}
```

Configure the automation step
------------------------------

1. Open an **Automation Configuration** and add or edit an **Activity** step.
2. In the **Activity** tab, select the template in the **Note Template** field.
3. The static **Summary** and **Note** fields are hidden when a template is selected,
as they are replaced by the rendered template output.
4. Save and start the automation as usual.

When the step runs, the template subject and body are rendered individually for
each target record and set as the activity summary and note respectively.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading