Skip to content

Conversation

@SamBachmann
Copy link
Contributor

@SamBachmann SamBachmann commented Dec 23, 2025

This PR migrates the interaction_resume module from Odoo v14 to v18.

Key changes:

  • UI/UX: Replaced deprecated tree views with the new list view type.
  • Framework: Converted legacy attrs (invisible/readonly/required) to standard v18 Python-like expressions.
  • JavaScript: Fully rewrote the frontend logic using OWL Components and the ListController patch to replace legacy Widgets.
  • Backend: Renamed the deprecated refresh() method to action_refresh() to comply with framework changes.

⚠️ Warning: Testing Status

I have successfully resolved all migration-related conflicts and ensured the module installs without manifest errors. However, I have not yet been able to fully verify the functional behavior in a live v18 environment due to local setup complexities. @ecino I would appreciate if you give me more info about the usage of this module.

@SamBachmann SamBachmann requested a review from ecino December 23, 2025 13:04
@SamBachmann SamBachmann self-assigned this Dec 23, 2025
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @SamBachmann, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances partner communication tracking by migrating and expanding the interaction_resume module. The core purpose is to provide a consolidated, chronological view of all interactions with a partner, drawing data from various Odoo applications. This improvement offers a clearer, more efficient way for users to understand and manage a partner's communication history, streamlining workflows and improving data accessibility.

Highlights

  • Migration of interaction_resume module: The interaction_resume module has been migrated, introducing a comprehensive timeline view for all communication exchanges with partners. This centralizes interaction history from various Odoo modules.
  • Unified Communication Timeline: This module integrates diverse communication types, including Phone calls, SMS, Emails, Mass Mailings, Support requests, and other logged interactions, into a single, easily accessible view on the partner record.
  • Interaction Data Fetching: A new mechanism is implemented to fetch and display interactions from multiple Odoo models such as partner.communication.job, crm.claim, crm.phonecall, sms.sms, mailing.trace, and partner.log.other.interaction.
  • Manual Interaction Logging and Message Conversion: A wizard is added to allow users to manually log 'other' types of interactions. Additionally, existing mail.message records can now be converted into other.interaction records for inclusion in the timeline.
  • Minor Documentation Formatting: Several README.rst and index.html files across various modules have received minor formatting adjustments, primarily removing extra spaces and improving list item indentation.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@SamBachmann
Copy link
Contributor Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request migrates the interaction_resume module, which introduces a timeline view of all communications with a partner. The changes include adding the new module with its models, views, wizards, and JS assets. My review focuses on the new interaction_resume module. I've found a couple of critical issues related to background job scheduling that could cause crashes, and a logic issue in determining interaction direction. I've also noted some minor issues in the JavaScript code.

Comment on lines +60 to +66
res.mapped("partner_id").with_delay(
channel="root.partner_communication",
priority=100,
identity_key=self.partner_id._name
+ ".fetch_interactions."
+ str(self.partner_id.id),
).fetch_interactions()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The identity_key for the with_delay call is constructed incorrectly. In the create method, self is an empty recordset, so self.partner_id is also empty, and self.partner_id.id will raise an error. Additionally, calling with_delay on a recordset with a static identity_key will result in all jobs having the same key, which is likely not the intended behavior.

To fix this, you should iterate over the partners and schedule a job for each with a unique identity_key.

        for partner in res.mapped("partner_id"):
            partner.with_delay(
                channel="root.partner_communication",
                priority=100,
                identity_key=f"res.partner.fetch_interactions.{partner.id}",
            ).fetch_interactions()

Comment on lines +66 to +72
self.partner_id.with_delay(
channel="root.partner_communication",
priority=100,
identity_key=self.partner_id._name
+ ".fetch_interactions."
+ str(self.partner_id.id),
).fetch_interactions()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The identity_key for the with_delay call is constructed incorrectly. The message_post method can be called on a recordset of crm.claim records. In that case, self.partner_id would be a recordset of partners, and self.partner_id.id would raise an error.

To fix this, you should iterate over the claims and schedule a job for each partner.

Suggested change
self.partner_id.with_delay(
channel="root.partner_communication",
priority=100,
identity_key=self.partner_id._name
+ ".fetch_interactions."
+ str(self.partner_id.id),
).fetch_interactions()
for claim in self:
if claim.partner_id:
claim.partner_id.with_delay(
channel="root.partner_communication",
priority=100,
identity_key=f"{claim.partner_id._name}.fetch_interactions.{claim.partner_id.id}",
).fetch_interactions()

Comment on lines +24 to +37
user = message.author_id.user_ids[:1] or message.create_uid or self.env.user
if user.share:
user = self.env.user
interactions += interactions.with_user(user).create(
{
"partner_id": partner_id,
"date": message.date,
"communication_type": "Email",
"subject": message.subject,
"body": message.body,
"other_type": "Direct message converted to interaction",
"direction": "out" if message.author_id.id != partner_id else "in",
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The logic to determine the interaction direction is a bit too simplistic. It only checks if the author is the partner for whom the interaction is being logged. This doesn't account for other contacts of the partner or other scenarios. A more robust approach would be to check if the author is one of the partner's related contacts, similar to the logic in crm_request.py.

            partner = self.env["res.partner"].browse(partner_id)
            partners = partner | partner.other_contact_ids
            if partner.email:
                partners |= self.env["res.partner"].with_context(
                    active_test=False
                ).search([("email", "=", partner.email)])
            user = message.author_id.user_ids[:1] or message.create_uid or self.env.user
            if user.share:
                user = self.env.user
            interactions += interactions.with_user(user).create(
                {
                    "partner_id": partner_id,
                    "date": message.date,
                    "communication_type": "Email",
                    "subject": message.subject,
                    "body": message.body,
                    "other_type": "Direct message converted to interaction",
                    "direction": "in" if message.author_id in partners else "out",
                }
            )

var self = this;
var res_ids = this.model.get(this.handle).res_ids;
if (!res_ids.length) {
console.log("No records to refresh");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This file contains several console.log and console.error statements (e.g., lines 22, 36, 44, 58, 67, 86, 89). These are useful for debugging but should be removed from production code to avoid cluttering the browser console. Please remove all of them.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new module interaction_resume to display a timeline of communications with partners. It also includes formatting fixes across several README.rst files. The new module is well-structured and covers various interaction sources like emails, phone calls, and SMS.

My review focuses on the new module. I've found a couple of important issues related to job queuing and data pagination that could lead to incorrect behavior. I've also suggested an improvement in the JavaScript code for better error handling and user experience.

Overall, this is a great addition. Once the identified issues are addressed, the module should be solid.

Comment on lines +58 to +67
def create(self, vals_list):
res = super().create(vals_list)
res.mapped("partner_id").with_delay(
channel="root.partner_communication",
priority=100,
identity_key=self.partner_id._name
+ ".fetch_interactions."
+ str(self.partner_id.id),
).fetch_interactions()
return res
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The identity_key for the delayed job is not generated correctly when creating multiple interactions at once. It uses self.partner_id, but self is an empty recordset in the context of the create method, resulting in a static key like 'res.partner.fetch_interactions.False'. This can cause jobs to be deduplicated incorrectly, leading to missed interaction updates for some partners if they are created in the same transaction.

To fix this, you should iterate over the created records and generate a unique identity_key for each partner.

Suggested change
def create(self, vals_list):
res = super().create(vals_list)
res.mapped("partner_id").with_delay(
channel="root.partner_communication",
priority=100,
identity_key=self.partner_id._name
+ ".fetch_interactions."
+ str(self.partner_id.id),
).fetch_interactions()
return res
def create(self, vals_list):
res = super().create(vals_list)
for partner in res.mapped("partner_id"):
partner.with_delay(
channel="root.partner_communication",
priority=100,
identity_key=f"{partner._name}.fetch_interactions.{partner.id}",
).fetch_interactions()
return res

for model in models:
self.env[model].fetch_interaction(self, since, until)
self.last_interaction_fetch_date = fields.Datetime.now()
self.last_interaction_fetch_page += page
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The pagination logic for fetching more interactions is incorrect. self.last_interaction_fetch_page += page will cause the page number to grow exponentially, leading to incorrect pagination and skipping of historical data. It should be set to the current page number being fetched to ensure linear pagination.

Suggested change
self.last_interaction_fetch_page += page
self.last_interaction_fetch_page = page

Comment on lines 35 to 37
.catch(function () {
console.log("Error refreshing record");
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error handling in this method uses console.log, which is not visible to end-users. It's better to use Odoo's notification service to display a user-friendly error message. This improves the user experience significantly.

Please apply this pattern to the _onFetchMore and _onLogInteraction methods as well.

        .catch(function (error) {
          self.displayNotification({ message: "Error refreshing record", type: "danger" });
          console.error("Error refreshing record:", error);
        });

Comment on lines 57 to 59
.catch(function () {
console.log("Error fetching more records");
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the _onRefresh method, the error handling here uses console.log. Please use the notification service to inform the user about the error, and log the error object to the console for debugging purposes.

        .catch(function (error) {
          self.displayNotification({ message: "Error fetching more records", type: "danger" });
          console.error("Error fetching more records:", error);
        });

Comment on lines 88 to 90
.catch(function (error) {
console.error("Error executing action:", error);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency and better user experience, please use the notification service to display an error message to the user in case the action fails.

        .catch(function (error) {
          self.displayNotification({ message: "Error executing action", type: "danger" });
          console.error("Error executing action:", error);
        });

@SamBachmann SamBachmann force-pushed the sBachmann/18.0-interaction_resume branch from 216161f to 63290e2 Compare December 23, 2025 15:42
@SamBachmann
Copy link
Contributor Author

@ecino As the idea is to simply migrate the module and not to totally refactor it, should I address gemini' review issues ?

@SamBachmann SamBachmann changed the title T2715 [MIG] Migration of interaction_resume module T2715 [MIG] interaction_resume: Migration to 18.0 Dec 24, 2025
@SamBachmann SamBachmann marked this pull request as ready for review December 24, 2025 07:50
[MIG] T2715 interaction_resume manual update of templates

[MIG] T2715 interaction_resume manual update of backend logic

[MIG] T2715 precommit

[MIG] T2715 REVERT changes in other folder
@ecino ecino force-pushed the sBachmann/18.0-interaction_resume branch from 63290e2 to 96b3733 Compare January 8, 2026 13:30
@ecino
Copy link
Member

ecino commented Jan 8, 2026

@SamBachmann I fixed some migration issues that prevented the installation (I forced pushed on the branch, you can fetch and reset your local branch to get the latest state). Now it hase OWL errors when trying to load the view which you can check. The module is adding the "Interaction Resume" button inside the partner view, which displays the history of all exchanged messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants