From fdf75cc33fecce3e5344ebc2002fb04802e43bcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nguy=E1=BB=85n=20=C4=90=E1=BA=A1i=20D=C6=B0=C6=A1ng?=
 <daiduongnguyen2709@gmail.com>
Date: Thu, 13 Jun 2024 15:19:05 +0700
Subject: [PATCH 1/2] [OU-ADD] hr_timesheet: migrate to 17.0

---
 docsource/modules160-170.rst                  |  2 +-
 .../hr_timesheet/17.0.1.0/post-migration.py   | 48 +++++++++++++++++++
 .../hr_timesheet/17.0.1.0/pre-migration.py    | 16 +++++++
 .../17.0.1.0/upgrade_analysis_work.txt        | 35 ++++++++++++++
 4 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
 create mode 100644 openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py
 create mode 100644 openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt

diff --git a/docsource/modules160-170.rst b/docsource/modules160-170.rst
index 6fba859261d8..e1e701f2005a 100644
--- a/docsource/modules160-170.rst
+++ b/docsource/modules160-170.rst
@@ -196,7 +196,7 @@ Module coverage 16.0 -> 17.0
 +---------------------------------------------------+----------------------+-------------------------------------------------+
 | hr_skills_survey                                  |                      |                                                 |
 +---------------------------------------------------+----------------------+-------------------------------------------------+
-| hr_timesheet                                      |                      |                                                 |
+| hr_timesheet                                      | Done                 |                                                 |
 +---------------------------------------------------+----------------------+-------------------------------------------------+
 | hr_timesheet_attendance                           |                      |                                                 |
 +---------------------------------------------------+----------------------+-------------------------------------------------+
diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
new file mode 100644
index 000000000000..f9c764c9a753
--- /dev/null
+++ b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
@@ -0,0 +1,48 @@
+from collections import defaultdict
+
+from openupgradelib import openupgrade
+
+
+def _project_update_fill_timesheet(env):
+    updates = env["project.update"].with_context(active_test=False).search([])
+    timesheets_read_group = env["account.analytic.line"]._read_group(
+        [
+            (
+                "project_id",
+                "in",
+                env["project.project"].with_context(active_test=False).search([]).ids,
+            )
+        ],
+        ["project_id", "product_uom_id", "date:day"],
+        ["unit_amount:sum"],
+    )
+    timesheet_time_dict = defaultdict(list)
+    for project, product_uom, date, unit_amount_sum in timesheets_read_group:
+        timesheet_time_dict[project.id].append((product_uom, date, unit_amount_sum))
+    for update in updates:
+        project = update.project_id
+        encode_uom = project.company_id.timesheet_encode_uom_id
+        if not encode_uom:
+            continue
+
+        total_time = 0.0
+        for product_uom, date, unit_amount in timesheet_time_dict[project.id]:
+            if date > update.date:
+                continue
+            factor = (product_uom or project.timesheet_encode_uom_id).factor_inv
+            total_time += unit_amount * (1.0 if project.encode_uom_in_days else factor)
+        total_time *= project.timesheet_encode_uom_id.factor
+
+        ratio = env.ref("uom.product_uom_hour").ratio / encode_uom.ratio
+        update.write(
+            {
+                "uom_id": encode_uom,
+                "allocated_time": round(project.allocated_hours / ratio),
+                "timesheet_time": round(total_time / ratio),
+            }
+        )
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+    _project_update_fill_timesheet(env)
diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py
new file mode 100644
index 000000000000..9d40529e6857
--- /dev/null
+++ b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py
@@ -0,0 +1,16 @@
+from openupgradelib import openupgrade
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+    openupgrade.rename_fields(
+        env,
+        [
+            (
+                "account.analytic.line",
+                "account_analytic_line",
+                "ancestor_task_id",
+                "parent_task_id",
+            )
+        ],
+    )
diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt
new file mode 100644
index 000000000000..5d1a124e3148
--- /dev/null
+++ b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt
@@ -0,0 +1,35 @@
+---Models in module 'hr_timesheet'---
+new model hr.employee.delete.wizard [transient]
+# NOTHING TO DO
+
+---Fields in module 'hr_timesheet'---
+hr_timesheet / account.analytic.line    / ancestor_task_id (many2one)   : DEL relation: project.task
+hr_timesheet / account.analytic.line    / parent_task_id (many2one)     : NEW relation: project.task, isrelated: related, stored
+# TODO pre-migration: rename field
+
+hr_timesheet / project.project          / timesheet_encode_uom_id (many2one): not related anymore
+hr_timesheet / project.project          / timesheet_encode_uom_id (many2one): now a function
+# NOTHING TO DO: no store field
+
+hr_timesheet / project.update           / allocated_time (integer)      : NEW
+hr_timesheet / project.update           / timesheet_time (integer)      : NEW
+hr_timesheet / project.update           / uom_id (many2one)             : NEW relation: uom.uom
+# DONE post-migration: fill value
+
+---XML records in module 'hr_timesheet'---
+DEL ir.actions.act_window.view: hr_timesheet.timesheet_action_view_from_employee_list
+NEW ir.actions.server: hr_timesheet.unlink_employee_action
+NEW ir.model.access: hr_timesheet.access_hr_employee_delete_wizard
+DEL ir.model.access: hr_timesheet.access_project_task
+NEW ir.ui.view: hr_timesheet.hr_employee_delete_wizard_form
+NEW ir.ui.view: hr_timesheet.portal_my_task_allocated_hours_template
+NEW ir.ui.view: hr_timesheet.project_update_view_kanban_inherit
+NEW ir.ui.view: hr_timesheet.view_employee_tree_inherit_timesheet
+DEL ir.ui.view: hr_timesheet.portal_my_task_planned_hours_template
+DEL ir.ui.view: hr_timesheet.project_sharing_inherit_project_task_view_tree
+DEL ir.ui.view: hr_timesheet.project_sharing_project_task_view_search_inherit_timesheet
+DEL ir.ui.view: hr_timesheet.rating_rating_view_search_project_inherited
+DEL ir.ui.view: hr_timesheet.report_project_task_user_view_search
+DEL ir.ui.view: hr_timesheet.report_project_task_user_view_tree
+DEL ir.ui.view: hr_timesheet.view_task_search_form_hr_extended
+# NOTHING TO DO: noupdate records

From 16f588b859e843f372d5b71305abe929dbbe95db Mon Sep 17 00:00:00 2001
From: "Pedro M. Baeza" <pedro.baeza@tecnativa.com>
Date: Mon, 31 Mar 2025 20:18:25 +0200
Subject: [PATCH 2/2] [OU-IMP] hr_timesheet: Finish migration scripts

TT50077
---
 .../hr_timesheet/17.0.1.0/post-migration.py   | 51 +++++++------------
 .../hr_timesheet/17.0.1.0/pre-migration.py    | 16 ------
 .../17.0.1.0/upgrade_analysis_work.txt        | 10 ++--
 3 files changed, 23 insertions(+), 54 deletions(-)
 delete mode 100644 openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py

diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
index f9c764c9a753..dd2e7c3781e9 100644
--- a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
+++ b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/post-migration.py
@@ -1,44 +1,27 @@
-from collections import defaultdict
-
+# Copyright 2024 Viindoo Technology Joint Stock Company (Viindoo)
+# Copyright 2025 Tecnativa - Pedro M. Baeza
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 from openupgradelib import openupgrade
 
 
 def _project_update_fill_timesheet(env):
-    updates = env["project.update"].with_context(active_test=False).search([])
-    timesheets_read_group = env["account.analytic.line"]._read_group(
-        [
-            (
-                "project_id",
-                "in",
-                env["project.project"].with_context(active_test=False).search([]).ids,
-            )
-        ],
-        ["project_id", "product_uom_id", "date:day"],
-        ["unit_amount:sum"],
-    )
-    timesheet_time_dict = defaultdict(list)
-    for project, product_uom, date, unit_amount_sum in timesheets_read_group:
-        timesheet_time_dict[project.id].append((product_uom, date, unit_amount_sum))
-    for update in updates:
+    """Fill existing project updates with the theoretical information about the number
+    of allocated and spent hours. It may be different from the ones existing on the
+    moment the project update was done if later modifications changed them.
+    """
+    uom_hour = env.ref("uom.product_uom_hour")
+    for update in env["project.update"].with_context(active_test=False).search([]):
         project = update.project_id
-        encode_uom = project.company_id.timesheet_encode_uom_id
-        if not encode_uom:
-            continue
-
-        total_time = 0.0
-        for product_uom, date, unit_amount in timesheet_time_dict[project.id]:
-            if date > update.date:
-                continue
-            factor = (product_uom or project.timesheet_encode_uom_id).factor_inv
-            total_time += unit_amount * (1.0 if project.encode_uom_in_days else factor)
-        total_time *= project.timesheet_encode_uom_id.factor
-
-        ratio = env.ref("uom.product_uom_hour").ratio / encode_uom.ratio
+        group = env["account.analytic.line"]._read_group(
+            [("project_id", "=", project.id), ("date", "<=", update.date)],
+            [],
+            ["unit_amount:sum"],
+        )[0]
         update.write(
             {
-                "uom_id": encode_uom,
-                "allocated_time": round(project.allocated_hours / ratio),
-                "timesheet_time": round(total_time / ratio),
+                "uom_id": uom_hour.id,
+                "allocated_time": round(project.allocated_hours),
+                "timesheet_time": round(group[0]),
             }
         )
 
diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py
deleted file mode 100644
index 9d40529e6857..000000000000
--- a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/pre-migration.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from openupgradelib import openupgrade
-
-
-@openupgrade.migrate()
-def migrate(env, version):
-    openupgrade.rename_fields(
-        env,
-        [
-            (
-                "account.analytic.line",
-                "account_analytic_line",
-                "ancestor_task_id",
-                "parent_task_id",
-            )
-        ],
-    )
diff --git a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt
index 5d1a124e3148..172b4d1e6bc4 100644
--- a/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt
+++ b/openupgrade_scripts/scripts/hr_timesheet/17.0.1.0/upgrade_analysis_work.txt
@@ -4,17 +4,19 @@ new model hr.employee.delete.wizard [transient]
 
 ---Fields in module 'hr_timesheet'---
 hr_timesheet / account.analytic.line    / ancestor_task_id (many2one)   : DEL relation: project.task
+# NOTHING TO DO: Removed field
+
 hr_timesheet / account.analytic.line    / parent_task_id (many2one)     : NEW relation: project.task, isrelated: related, stored
-# TODO pre-migration: rename field
+# NOTHING TO DO: ORM already fills it efficiently being a 2 level depth related field
 
 hr_timesheet / project.project          / timesheet_encode_uom_id (many2one): not related anymore
 hr_timesheet / project.project          / timesheet_encode_uom_id (many2one): now a function
-# NOTHING TO DO: no store field
+# NOTHING TO DO: non stored field
 
 hr_timesheet / project.update           / allocated_time (integer)      : NEW
 hr_timesheet / project.update           / timesheet_time (integer)      : NEW
 hr_timesheet / project.update           / uom_id (many2one)             : NEW relation: uom.uom
-# DONE post-migration: fill value
+# DONE: post-migration: fill historical values with the aproximation of current data (there can be differences if in the moment of creating the update, the allocated hours or the timesheets were not the same as today)
 
 ---XML records in module 'hr_timesheet'---
 DEL ir.actions.act_window.view: hr_timesheet.timesheet_action_view_from_employee_list
@@ -32,4 +34,4 @@ DEL ir.ui.view: hr_timesheet.rating_rating_view_search_project_inherited
 DEL ir.ui.view: hr_timesheet.report_project_task_user_view_search
 DEL ir.ui.view: hr_timesheet.report_project_task_user_view_tree
 DEL ir.ui.view: hr_timesheet.view_task_search_form_hr_extended
-# NOTHING TO DO: noupdate records
+# NOTHING TO DO: noupdate=0 records
