Repository
OCA/project · module folder · Try on Runboat
Module version
1.0.0
Category
Project
Folder size
0.35 MB
License
AGPL-3
Application
Yes
Auto-installable
No
Website
https://github.com/OCA/project
Last tracking update
2026-08-07 08:42:45
Authors
Camptocamp, Odoo Community Association (OCA)
Maintainers
Camptocamp, Odoo Community Association (OCA)
Committers
Weblate, OCA-git-bot, oca-ci, solomonprabu
Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
None
Description
This module allows to plan your resources using forecast lines.

For each employee of the company, the module will generate forecast line
records with a positive capacity based on their working time schedules.
Then, tasks assigned to employees will generate forecast lines with a
negative capacity which will "consume" the work time capacity of the
employees.

The idea is that you can then see the work capacity and scheduled work
of people by summing the "forecasts" per time period. If you have more
resources (positive forecast) than work (negative forecast) you will
have a positive net sum. Otherwise you are in trouble and need to
recruit or reschedule your work. Another way to use the report is
checking when the work capacity of a department becomes positive (or
high enough) in order to provide you potential customers with an
estimate of when a project would be able to start.

Forecast lines also come in two states "forecast" or "confirmed",
depending on whether the consumption is confirmed or not. For instance,
holidays requests and sales quotation lines create lines of type
"forecast", whereas tasks for project which are in a running state
create lines with type "confirmed".

To get the best experience using the Forecast application you may want
to install:

- project_forecast_line_holidays_public module which takes public
  holidays into account during forecast lines creation
- project_forecast_line_bokeh_chart module which improves the reports of
  project_forecast_line module by using the bokeh widget available in
  OCA/web

Code Analysis

Views touched (17)
XML IDNameModelTypeStatus
product_template_form product.template form Inherits product.product_template_only_form_view
project_project_stage_view_form project.project.stage form Inherits project.project_project_stage_view_form
project_project_stage_view_form_quick_create project.project.stage form Inherits project.project_project_stage_view_form_quick_create
project_project_stage_view_tree project.project.stage tree Inherits project.project_project_stage_view_tree
res_config_settings_view_form res.config.settings.view.form.inherit.forecast res.config.settings form Inherits base.res_config_settings_view_form
view_employee_form hr.employee form Inherits hr.view_employee_form
view_forecast_line_graph forecast.line graph New
view_forecast_line_graph_stacked forecast.line graph New
view_forecast_line_list forecast.line list New
view_forecast_line_pivot forecast.line pivot New
view_forecast_line_search forecast.line search New
view_forecast_role_form forecast.role form New
view_forecast_role_list forecast.role list New
view_forecast_role_search forecast.role search New
view_hr_job_form hr.job form Inherits hr.view_hr_job_form
view_order_form sale.order form Inherits sale.view_order_form
view_task_form project.task form Inherits project.view_task_form2
HTTP endpoints (0)

No HTTP endpoints found for this module.

Models touched (15)

New fields (22)
  • company_id Many2one → res.company
    default=<expr> required=True args: 'res.company'
  • confirmed_consolidated_forecast Float
    compute='_compute_consolidated_forecast' digits=(12, 5) help='Consolidated forecast for lines of type confirmed' store=True string='Confirmed lines consolidated forecast'
  • consolidated_forecast Float
    compute='_compute_consolidated_forecast' digits=(12, 5) help='Consolidated forecast for lines of all types consumed' store=True
  • cost Monetary
    help='Cost, in company currency. Cost is positive for things which add forecast, such as employees and negative for things which consume forecast such as holidays, sales, or tasks. '
  • currency_id Many2one
    related='company_id.currency_id' store=True
  • date_from Date
    help='Date of the period start for this line' required=True
  • date_to Date
    required=True
  • employee_forecast_role_id Many2one → hr.employee.forecast.role
    ondelete='cascade' string='Employee Forecast Role' args: 'hr.employee.forecast.role'
  • employee_id Many2one → hr.employee
    ondelete='cascade' string='Employee' args: 'hr.employee'
  • employee_resource_consumption_ids One2many → forecast.line
    args: 'forecast.line', 'employee_resource_forecast_line_id'
  • employee_resource_forecast_line_id Many2one → forecast.line
    compute='_compute_employee_forecast_line_id' help='technical field giving the name of the resource (model=hr.employee.forecast.role) line for that employee and that period' index=True ondelete='set null' store=True args: 'forecast.line'
  • forecast_hours Float
    help='Forecast (in hours). Forecast is positive for resources which add forecast, such as employees, and negative for things which consume forecast, such as holidays, sales, or tasks.' args: 'Forecast'
  • forecast_role_id Many2one → forecast.role
    index=True ondelete='restrict' required=True string='Forecast role' args: 'forecast.role'
  • hr_leave_id Many2one → hr.leave
    index=True ondelete='cascade' string='Leave' args: 'hr.leave'
  • name Char
    required=True
  • project_id Many2one → project.project
    index=True ondelete='cascade' string='Project' args: 'project.project'
  • res_id Integer
    index=True string='Record ID'
  • res_model Char
    index=True string='Model'
  • sale_id Many2one → sale.order
    index=True related='sale_line_id.order_id' store=True string='Sale' args: 'sale.order'
  • sale_line_id Many2one → sale.order.line
    index=True ondelete='cascade' string='Sale line' args: 'sale.order.line'
  • task_id Many2one → project.task
    index=True ondelete='cascade' string='Task' args: 'project.task'
  • type Selection
    default='forecast' required=True args: [('forecast', 'Forecast'), ('confirmed', 'Confirmed')]
Public methods (4)
  • convert_days_to_hours(self, days)
    @api.model
  • create(self, vals_list)
    @api.model_create_multi@api.returns('self', <expr>)
  • unlink(self)
  • write(self, vals)

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (2)
  • description Text
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (2)
  • main_role_id Many2one → forecast.role
    compute='_compute_main_role_id' groups='hr.group_hr_user' ondelete='restrict' args: 'forecast.role'
  • role_ids One2many → hr.employee.forecast.role
    groups='hr.group_hr_user' args: 'hr.employee.forecast.role', 'employee_id'
Public methods (2)
  • create(self, values)
    @api.model_create_multi@api.returns('self', <expr>)
  • write(self, values)

New fields (7)
  • company_id Many2one
    related='employee_id.company_id' store=True
  • date_end Date
  • date_start Date
    default=fields.Date.today required=True
  • employee_id Many2one → hr.employee
    ondelete='cascade' required=True args: 'hr.employee'
  • rate Integer
    default=100
  • role_id Many2one → forecast.role
    required=True args: 'forecast.role'
  • sequence Integer
Public methods (2)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, values)

New fields (1)
  • role_id Many2one → forecast.role
    ondelete='restrict' args: 'forecast.role'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (2)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, values)

New fields (1)
  • forecast_role_id Many2one → forecast.role
    ondelete='restrict' args: 'forecast.role'
Public methods (0)

No public methods.

New fields (1)
  • forecast_line_type Selection
    help='type of forecast lines created by the tasks of projects in that stage' args: [('forecast', 'Forecast'), ('confirmed', 'Confirmed')]
Public methods (0)

No public methods.

New fields (4)
  • forecast_date_planned_end Date
    args: 'Planned end date'
  • forecast_date_planned_start Date
    args: 'Planned start date'
  • forecast_recomputation_trigger Float
    compute='_compute_forecast_recomputation_trigger' help='Technical field used to trigger the forecast recomputation' store=True
  • forecast_role_id Many2one → forecast.role
    ondelete='restrict' args: 'forecast.role'
Public methods (3)
  • onchange_user_ids(self)
    @api.onchange('user_ids')
  • set_forecast_type(self)
  • write(self, values)

New fields (2)
  • forecast_line_granularity Selection
    default='month' help='Periodicity of the forecast that will be generated' args: [('day', 'Day'), ('week', 'Week'), ('month', 'Month')]
  • forecast_line_horizon Integer
    default=12 help='Number of month for the forecast planning'
Public methods (1)
  • write(self, values)

New fields (3)
  • forecast_line_granularity Selection
    readonly=False related='company_id.forecast_line_granularity'
  • forecast_line_horizon Integer
    readonly=False related='company_id.forecast_line_horizon'
  • group_forecast_line_on_quotation Boolean
    implied_group='project_forecast_line.group_forecast_line_on_quotation' args: 'Forecast Line on Quotations'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (3)
  • create(self, vals_list)
    @api.model_create_multi
  • unlink(self)
  • write(self, values)

New fields (2)
  • default_forecast_date_end Date
  • default_forecast_date_start Date
Public methods (3)
  • action_cancel(self)
  • action_confirm(self)
  • write(self, values)

New fields (2)
  • forecast_date_end Date
  • forecast_date_start Date
Public methods (1)
  • create(self, vals_list)
    @api.model_create_multi

Loading…

Loading…