Skip to content

T3206-Correct-existing-translation-data#2098

Open
jordyBSK wants to merge 7 commits into
18.0from
T3206-Correct-existing-translation-data
Open

T3206-Correct-existing-translation-data#2098
jordyBSK wants to merge 7 commits into
18.0from
T3206-Correct-existing-translation-data

Conversation

@jordyBSK

Copy link
Copy Markdown
Contributor

refactor: count only completed translations in stats

  • Update nb_translated_letters to filter on translation_status == "done"
  • Replace translate_date usage with translate_done for yearly stats
  • Add precise @api.depends on translation_status and translate_done
  • Ensure counters reflect only completed translations

- Update nb_translated_letters to filter on translation_status == "done"
- Replace translate_date usage with translate_done for yearly stats
- Add precise @api.depends on translation_status and translate_done
- Ensure counters reflect only completed translations

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

Copy link
Copy Markdown
Contributor

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 updates the computed fields tracking translated letters to filter by status and date. The reviewer suggests optimizing these computations by replacing the in-memory Python filtering on the One2many field with database-level aggregations using read_group to prevent performance degradation and high memory usage.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +56 to +63
@api.depends("translated_letter_ids.translation_status")
def _compute_nb_translated_letters(self):
for translator in self:
translator.nb_translated_letters = len(translator.translated_letter_ids)
translator.nb_translated_letters = len(
translator.translated_letter_ids.filtered(
lambda it: it.translation_status == "done"
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Using filtered on a One2many field (translated_letter_ids) loads all associated correspondence records into memory. For translators with a large history of letters, this can cause significant performance degradation and high memory usage. Since this is a stored computed field, it will be recomputed frequently. Using read_group allows Odoo to perform a single optimized SQL aggregation query, which is much faster and avoids loading any records into memory.

    @api.depends("translated_letter_ids.translation_status")
    def _compute_nb_translated_letters(self):
        groups = self.env["correspondence"].read_group(
            [("new_translator_id", "in", self.ids), ("translation_status", "=", "done")],
            ["new_translator_id"],
            ["new_translator_id"]
        )
        mapped_data = {
            g["new_translator_id"][0]: g["new_translator_id_count"]
            for g in groups
            if g["new_translator_id"]
        }
        for translator in self:
            translator.nb_translated_letters = mapped_data.get(translator.id, 0)

Comment on lines 65 to 75
@api.depends("translated_letter_ids.translation_status", "translated_letter_ids.translate_done")
def _compute_nb_translated_letters_this_year(self):
current_year = fields.Datetime.now().year
for translator in self:
translator.nb_translated_letters_this_year = len(
translator.translated_letter_ids.filtered(
lambda it: it.translate_date
and it.translate_date.year == fields.Datetime.now().year
lambda it: it.translation_status == "done" and
it.translate_done and
it.translate_done.year == current_year
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Filtering the One2many field in Python to count letters for the current year loads all correspondence records into memory. We can optimize this by using read_group with a date range filter on translate_done directly in the database query, which avoids loading records and executes a highly efficient database-level aggregation.

    @api.depends("translated_letter_ids.translation_status", "translated_letter_ids.translate_done")
    def _compute_nb_translated_letters_this_year(self):
        current_year = fields.Datetime.now().year
        groups = self.env["correspondence"].read_group(
            [
                ("new_translator_id", "in", self.ids),
                ("translation_status", "=", "done"),
                ("translate_done", ">=", f"{current_year}-01-01 00:00:00"),
                ("translate_done", "<=", f"{current_year}-12-31 23:59:59"),
            ],
            ["new_translator_id"],
            ["new_translator_id"]
        )
        mapped_data = {
            g["new_translator_id"][0]: g["new_translator_id_count"]
            for g in groups
            if g["new_translator_id"]
        }
        for translator in self:
            translator.nb_translated_letters_this_year = mapped_data.get(translator.id, 0)

Comment on lines 77 to 87
@api.depends("translated_letter_ids.translation_status", "translated_letter_ids.translate_done")
def _compute_nb_translated_letters_last_year(self):
last_year = fields.Datetime.now().year - 1
for translator in self:
translator.nb_translated_letters_last_year = len(
translator.translated_letter_ids.filtered(
lambda it: it.translate_date
and it.translate_date.year == fields.Datetime.now().year - 1
lambda it: it.translation_status == "done" and
it.translate_done and
it.translate_done.year == last_year
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Similar to the current year computation, filtering the One2many field in Python to count letters for the last year loads all correspondence records into memory. Using read_group with a date range filter on translate_done directly in the database query avoids loading records and executes a highly efficient database-level aggregation.

Suggested change
@api.depends("translated_letter_ids.translation_status", "translated_letter_ids.translate_done")
def _compute_nb_translated_letters_last_year(self):
last_year = fields.Datetime.now().year - 1
for translator in self:
translator.nb_translated_letters_last_year = len(
translator.translated_letter_ids.filtered(
lambda it: it.translate_date
and it.translate_date.year == fields.Datetime.now().year - 1
lambda it: it.translation_status == "done" and
it.translate_done and
it.translate_done.year == last_year
)
)
@api.depends("translated_letter_ids.translation_status", "translated_letter_ids.translate_done")
def _compute_nb_translated_letters_last_year(self):
last_year = fields.Datetime.now().year - 1
groups = self.env["correspondence"].read_group(
[
("new_translator_id", "in", self.ids),
("translation_status", "=", "done"),
("translate_done", ">=", f"{last_year}-01-01 00:00:00"),
("translate_done", "<=", f"{last_year}-12-31 23:59:59"),
],
["new_translator_id"],
["new_translator_id"]
)
mapped_data = {
g["new_translator_id"][0]: g["new_translator_id_count"]
for g in groups
if g["new_translator_id"]
}
for translator in self:
translator.nb_translated_letters_last_year = mapped_data.get(translator.id, 0)

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The change is merge-safe based on the focused stats logic and migration refresh.

The updated domains and stored-field dependencies align with the stated goal of counting only completed translations, and no issues were identified in the changed files.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex captured translation stats before and after from the same executable run to verify counter behavior.
  • T-Rex captured depends recompute before/after states showing status and date mutations in the same run.
  • T-Rex captured migration recompute path before/after states from the same executable run.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (6): Last reviewed commit: "feat: add the migration file to calculat..." | Re-trigger Greptile

Comment thread sbc_translation/models/translation_user.py
Comment thread sbc_translation/models/translation_user.py

@NoeBerdoz NoeBerdoz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for your work on this! The refactor direction looks great, however, there is a key issue to fix before we can merge your proposal.

You changed the compute method, but not the existing data in the database:
Because these fields have store=True, Odoo will not automatically recompute the old rows during an upgrade. It will just keep reading the old, incorrect values. To fix this and meet the ticket requirements, we need a migration script to backfill the data and force a recompute for existing records.

Let me know if you need help setting up the migration script!

Comment on lines +104 to +111
@api.depends(
"translated_letter_ids.translation_status",
"translated_letter_ids.translate_done",
)
@api.depends(
"translated_letter_ids.translation_status",
"translated_letter_ids.translate_done",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like a code duplication to remove

Suggested change
@api.depends(
"translated_letter_ids.translation_status",
"translated_letter_ids.translate_done",
)
@api.depends(
"translated_letter_ids.translation_status",
"translated_letter_ids.translate_done",
)
@api.depends(
"translated_letter_ids.translation_status",
"translated_letter_ids.translate_done",
)

Comment thread sbc_translation/models/translation_user.py
Comment on lines +22 to +26
translators.flush_model([
"nb_translated_letters",
"nb_translated_letters_this_year",
"nb_translated_letters_last_year"
]) No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Queued Counters Stay Stale

When this migration runs, env.add_to_compute() only queues these stored fields for recomputation; flush_model() flushes cached values but does not drain the recompute queue. Existing translation.user rows can keep their old inflated counters after upgrade, so the dashboard API continues to return the pre-change totals until another write happens to trigger a recompute.

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.

2 participants