Skip to content

Commit

Permalink
[MIG] project_forecast_line: Migration to 16.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ntsirintanis committed Apr 29, 2024
1 parent c7fed8e commit a5080b7
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 36 deletions.
2 changes: 1 addition & 1 deletion project_forecast_line/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Project Forecast Lines
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b255437243142fe16938f1ea597859a0e0f286aa510e66d4e0a5646b7228478a
!! source digest: sha256:f6a3feb1d9b6593b5322c73cc13b475f38f01898496e691b2b2efc14fe320404
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
Expand Down
2 changes: 1 addition & 1 deletion project_forecast_line/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"name": "Project Forecast Lines",
"summary": "Project Forecast Lines",
"version": "15.0.1.3.3",
"version": "16.0.1.0.0",
"author": "Camptocamp SA, Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Project",
Expand Down
2 changes: 1 addition & 1 deletion project_forecast_line/models/forecast_line_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ForecastLineModelMixin(models.Model):

def _get_forecast_lines(self, domain=None):
self.ensure_one()
base_domain = [("res.model", "=", self._name), ("res_id", "=", self.id)]
base_domain = [("res_model", "=", self._name), ("res_id", "=", self.id)]
if domain is not None:
base_domain += domain
return self.env["forecast.line"].search(base_domain)
2 changes: 1 addition & 1 deletion project_forecast_line/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def _update_forecast_lines(self):
date_from=date_start,
date_to=date_end,
forecast_hours=forecast * rec.rate / 100.0,
unit_cost=rec.employee_id.timesheet_cost, # XXX to check
unit_cost=rec.employee_id.hourly_cost, # XXX to check
ttype="confirmed",
forecast_role_id=rec.role_id.id,
employee_id=rec.employee_id.id,
Expand Down
2 changes: 1 addition & 1 deletion project_forecast_line/models/hr_leave.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _update_forecast_lines(self):
forecast_hours=ForecastLine.convert_days_to_hours(
-1 * leave.number_of_days
),
unit_cost=leave.employee_id.timesheet_cost,
unit_cost=leave.employee_id.hourly_cost,
forecast_role_id=leave.employee_id.main_role_id.id,
hr_leave_id=leave.id,
employee_id=leave.employee_id.id,
Expand Down
4 changes: 2 additions & 2 deletions project_forecast_line/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ def _write(self, values):
return res

@api.onchange("product_id")
def product_id_change(self):
res = super().product_id_change()
def _onchange_product_id_warning(self):
res = super()._onchange_product_id_warning()
for line in self:
if not line.product_id.forecast_role_id:
line.forecast_date_start = False
Expand Down
2 changes: 1 addition & 1 deletion project_forecast_line/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ <h1 class="title">Project Forecast Lines</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b255437243142fe16938f1ea597859a0e0f286aa510e66d4e0a5646b7228478a
!! source digest: sha256:f6a3feb1d9b6593b5322c73cc13b475f38f01898496e691b2b2efc14fe320404
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/project/tree/16.0/project_forecast_line"><img alt="OCA/project" src="https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/project-16-0/project-16-0-project_forecast_line"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/project&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows to plan your resources using forecast lines.</p>
Expand Down
58 changes: 30 additions & 28 deletions project_forecast_line/tests/test_forecast_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def setUpClass(cls):
"name": "development time and material",
"detailed_type": "service",
"service_tracking": "task_in_project",
"price": 95,
"price_extra": 95,
"standard_price": 75,
"forecast_role_id": cls.role_developer.id,
"uom_id": cls.env.ref("uom.product_uom_hour").id,
Expand All @@ -85,7 +85,7 @@ def setUpClass(cls):
"name": "consultant time and material",
"detailed_type": "service",
"service_tracking": "task_in_project",
"price": 100,
"price_extra": 100,
"standard_price": 80,
"forecast_role_id": cls.role_consultant.id,
"uom_id": cls.env.ref("uom.product_uom_hour").id,
Expand All @@ -98,7 +98,7 @@ def setUpClass(cls):
"name": "pm time and material",
"detailed_type": "service",
"service_tracking": "task_in_project",
"price": 120,
"price_extra": 120,
"standard_price": 100,
"forecast_role_id": cls.role_consultant.id,
"uom_id": cls.env.ref("uom.product_uom_hour").id,
Expand Down Expand Up @@ -187,7 +187,7 @@ def test_employee_forecast_change_roles(self):
# employee becomes 50% consultant, 50% PM on Feb 1st
roles = self.employee_consultant.role_ids
roles.write({"date_end": "2022-01-31"})
self.env["base"].flush()
self.env["base"].flush_model()
lines = self.env["forecast.line"].search(
[
("employee_id", "=", self.employee_consultant.id),
Expand Down Expand Up @@ -215,7 +215,7 @@ def test_employee_forecast_change_roles(self):
},
]
)
self.env["base"].flush()
self.env["base"].flush_model()
lines = self.env["forecast.line"].search(
[
("employee_id", "=", self.employee_consultant.id),
Expand Down Expand Up @@ -254,7 +254,7 @@ def test_forecast_with_calendar(self):
"time_type": "leave",
}
)
self.env["base"].flush()
self.env["base"].flush_model()
lines = self.env["forecast.line"].search(
[
("employee_id", "=", self.employee_dev.id),
Expand Down Expand Up @@ -282,20 +282,21 @@ def _create_sale(
):
with Form(self.env["sale.order"]) as form:
form.partner_id = self.customer
form.date_order = "2022-01-10 08:00:00"
form.default_forecast_date_start = default_forecast_date_start
form.default_forecast_date_end = default_forecast_date_end
with form.order_line.new() as line:
line.product_id = self.product_dev_tm
line.product_uom_qty = uom_qty # 1 FTE sold
line.product_uom = self.env.ref("uom.product_uom_day")
so = form.save()
so.date_order = "2022-01-10 08:00:00"
so.default_forecast_date_start = default_forecast_date_start
so.default_forecast_date_end = default_forecast_date_end
return so

@freeze_time("2022-01-01")
def test_draft_sale_order_creates_negative_forecast_forecast(self):
so = self._create_sale("2022-02-07", "2022-02-20")
line = so.order_line[0]
line._onchange_product_id_warning()
self.assertEqual(line.forecast_date_start, date(2022, 2, 7))
self.assertEqual(line.forecast_date_end, date(2022, 2, 20))
forecast_lines = self.env["forecast.line"].search(
Expand Down Expand Up @@ -333,6 +334,7 @@ def test_draft_sale_order_without_dates_no_forecast(self):
"""a draft sale order with no dates on the line does not create forecast"""
so = self._create_sale("2022-02-07", False)
line = so.order_line[0]
line._onchange_product_id_warning()
self.assertEqual(line.forecast_date_start, date(2022, 2, 7))
self.assertEqual(line.forecast_date_end, False)
forecast_lines = self.env["forecast.line"].search(
Expand All @@ -348,6 +350,7 @@ def test_draft_sale_order_forecast_spread(self):
so = self._create_sale("2022-02-07", "2022-04-17", uom_qty=100)

line = so.order_line[0]
line._onchange_product_id_warning()
self.assertEqual(line.forecast_date_start, date(2022, 2, 7))
self.assertEqual(line.forecast_date_end, date(2022, 4, 17))
forecast_lines = self.env["forecast.line"].search(
Expand Down Expand Up @@ -424,16 +427,16 @@ def test_timesheet_forecast_lines(self):
with freeze_time("2022-01-01"):
with Form(self.env["sale.order"]) as form:
form.partner_id = self.customer
form.date_order = "2022-01-10 08:00:00"
form.default_forecast_date_start = "2022-02-14"
form.default_forecast_date_end = "2022-04-17"
with form.order_line.new() as line:
line.product_id = self.product_dev_tm
line.product_uom_qty = (
45 * 2
) # 45 working days in the period, sell 2 FTE
line.product_uom = self.env.ref("uom.product_uom_day")
so = form.save()
so.date_order = "2022-01-10 08:00:00"
so.default_forecast_date_start = "2022-02-14"
so.default_forecast_date_end = "2022-04-17"
so.action_confirm()

with freeze_time("2022-02-14"):
Expand All @@ -448,7 +451,7 @@ def test_timesheet_forecast_lines(self):
"unit_amount": 8,
}
)
task.flush()
task.flush_recordset()
forecast_lines = self.env["forecast.line"].search(
[("res_id", "=", task.id), ("res_model", "=", "project.task")]
)
Expand Down Expand Up @@ -538,7 +541,7 @@ def setUpClass(cls):
# flush needed here to trigger the recomputation with the correct
# frozen time (otherwise it is called by the test runner before the
# tests, outside of the context manager.
cls.task.flush()
cls.task.flush_recordset()

@freeze_time("2022-02-01 12:00:00")
def test_task_unlink(self):
Expand All @@ -557,7 +560,7 @@ def test_task_forecast_line_reschedule_employee(self):
)
self.assertEqual(task_forecast.mapped("employee_id"), self.employee_consultant)
self.task.user_ids = self.user_pm
self.task.flush()
self.task.flush_recordset()
task_forecast_after = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
Expand All @@ -578,7 +581,7 @@ def test_task_forecast_line_reschedule_dates(self):
"forecast_date_planned_end": "2022-02-16",
}
)
self.task.flush()
self.task.flush_recordset()
task_forecast_after = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
Expand All @@ -595,13 +598,13 @@ def test_task_forecast_line_reschedule_dates(self):
def test_task_forecast_line_reschedule_time(self):
"""changing the remaining time will keep the forecast lines"""
self.task.user_ids = self.user_consultant
self.task.flush()
self.task.flush_recordset()
task_forecast = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
self.assertEqual(task_forecast.mapped("forecast_hours"), [-8, -8])
self.task.write({"planned_hours": 24})
self.task.flush()
self.task.flush_recordset()
task_forecast_after = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
Expand All @@ -612,13 +615,13 @@ def test_task_forecast_line_reschedule_time(self):
def test_task_forecast_line_reschedule_time_no_employee(self):
"""changing the remaining time will keep the forecast lines, even when no
employee assigned"""
self.task.flush()
self.task.flush_recordset()
task_forecast = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
self.assertEqual(task_forecast.mapped("forecast_hours"), [-8, -8])
self.task.write({"planned_hours": 24})
self.task.flush()
self.task.flush_recordset()
task_forecast_after = self.env["forecast.line"].search(
[("task_id", "=", self.task.id)]
)
Expand Down Expand Up @@ -682,7 +685,7 @@ def test_task_forecast_lines_consolidated_forecast(self):
project_1 = ProjectProject.create({"name": "TestProject1"})
# set project in stage "to do" to get forecast
project_1.stage_id = self.env.ref("project.project_project_stage_0")
project_1.flush()
project_1.flush_recordset()
task_values = {
"project_id": project_1.id,
"forecast_role_id": self.role_consultant.id,
Expand All @@ -696,11 +699,10 @@ def test_task_forecast_lines_consolidated_forecast(self):
task_values.update({"name": "Task2"})
task_2 = ProjectTask.create(task_values)
task_2.user_ids = self.user_consultant

# Project 2 is in stage "in rogress" to get forecast
project_2 = ProjectProject.create({"name": "TestProject2"})
project_2.stage_id = self.env.ref("project.project_project_stage_1")
project_2.flush()
project_2.flush_recordset()
task_values.update({"project_id": project_2.id, "name": "Task3"})
task_3 = ProjectTask.create(task_values)
task_3.user_ids = self.user_consultant
Expand Down Expand Up @@ -768,7 +770,7 @@ def test_forecast_with_holidays(self):
# create new ones -> we check that the project task lines are
# automatically related to the new newly created employee role lines.
leave_request.action_validate()
leave_request.flush()
leave_request.flush_recordset()
forecast_lines = self.env["forecast.line"].search(
[
("employee_id", "=", self.employee_consultant.id),
Expand Down Expand Up @@ -803,7 +805,7 @@ def test_task_forecast_lines_consolidated_forecast_overallocation(self):
project = ProjectProject.create({"name": "TestProject"})
# set project in stage "in progress" to get confirmed forecast
project.stage_id = self.env.ref("project.project_project_stage_1")
project.flush()
project.flush_recordset()
task = ProjectTask.create(
{
"name": "Task1",
Expand Down Expand Up @@ -847,7 +849,7 @@ def test_task_forecast_lines_consolidated_forecast_overallocation_multiple_tasks
project = ProjectProject.create({"name": "TestProject"})
# set project in stage "in progress" to get confirmed forecast
project.stage_id = self.env.ref("project.project_project_stage_1")
project.flush()
project.flush_recordset()
task1 = ProjectTask.create(
{
"name": "Task1",
Expand Down Expand Up @@ -929,7 +931,7 @@ def test_task_forecast_lines_employee_different_roles(self):
project = ProjectProject.create({"name": "TestProjectDiffRoles"})
# set project in stage "in progress" to get confirmed forecast
project.stage_id = self.env.ref("project.project_project_stage_1")
project.flush()
project.flush_recordset()
task = ProjectTask.create(
{
"name": "TaskDiffRoles",
Expand Down Expand Up @@ -998,7 +1000,7 @@ def test_task_forecast_lines_employee_main_role(self):
project = ProjectProject.create({"name": "TestProjectDiffRoles"})
# set project in stage "in progress" to get confirmed forecast
project.stage_id = self.env.ref("project.project_project_stage_1")
project.flush()
project.flush_recordset()
task = ProjectTask.create(
{
"name": "TaskDiffRoles",
Expand Down

0 comments on commit a5080b7

Please sign in to comment.