Repository
odoo/odoo · module folder
Module version
0.1.0
Category
Sales/Sales
Folder size
5.35 MB
License
LGPL-3
Application
No
Auto-installable
Yes
Website
None
Last tracking update
2026-08-16 22:12:28
Authors
Odoo S.A.
Maintainers
Odoo S.A.
Committers
Xavier Morel, Raphael Collet, Thibault Delavallée, Stéphane Bidoul, Odoo Translation Bot, Lucas Perais (lpe), Yannick Tivisse, Julien Castiaux, Victor Feyens, Andrea Grazioso (agr-odoo), Paul Morelle, Julien Mougenot, svs-odoo, Prakash Prajapati, Tiffany Chang (tic), Gorash, Mathieu Duckerts-Antoine, William Braeckman, william-andre, Audric Onockx (auon), Renaud Thiry, Vincent Larcin, Louis Wicket (wil), alsh-odoo, Victor Piryns (pivi), Pierre-Yves Dufays, Levi Siuzdak (sile), Dylan Kiss (dyki), Antoine Boonen, Xavier Bol (xbo), Brieuc-brd, rajh-odoo, Youssef Bashandy, bary, Maxime de Neuville, suth-odoo, kcv-odoo, Tanguy Quéguineur, nihp-odoo, aamo-odoo, thle-odoo, Mathieu Coutant, Patricia Daloze (pda), guce, Pierre Pulinckx (PIPU), Kawtar Drissi El Bouzaidi (kdeb), David Van Droogenbroeck (DROD), Mohammad Abdulmoneim (abdu), Pierre Pulinckx, Bastien PIERRE, Michaël Mattiello, K Theja (kthe), Mahdi Alijani (malj), bona-odoo, Krzysztof Magusiak (krma), Maeva De Keyser (MDEK), Harrison Hutton, nsirjacobs, mjvi-odoo, bhra-odoo, defl, mohannedah, Quentin Colla (qucol), Amr Elkhatieb, Maxime de Neuville (mane), YoussefM890, damrOdoo, Merlin Guillaume, Abdelouahab Laaroussi (abla), Farah (ahmfa), ksin-odoo, chpa-odoo, Dhruvkumar Nagar
Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
project_task_analytic_propagation, sale_order_update_timesheet_price, sale_timesheet_invoice_link, sale_timesheet_line_exclude, sale_timesheet_margin, sale_timesheet_timeline, spreadsheet_dashboard_sale_timesheet, test_main_flows
Description
Allows to sell timesheets in your sales order
=============================================

This module set the right product on all timesheet lines
according to the order/contract you work on. This allows to
have real delivered quantities in sales orders.

Code Analysis

Views touched (45)
XML IDNameModelTypeStatus
account_invoice_view_form_inherit_sale_timesheet account.invoice.form.inherit.timesheet account.move form Inherits account.view_move_form
hr_timesheet_line_form_inherit account.analytic.line.form.inherit account.analytic.line form Inherits hr_timesheet.hr_timesheet_line_form
hr_timesheet_line_tree_inherit account.analytic.line.list.inherit account.analytic.line list Inherits hr_timesheet.hr_timesheet_line_tree
hr_timesheet_report_search_sale_timesheet timesheets.analysis.report.search timesheets.analysis.report search Inherits sale_timesheet.timesheet_view_search
portal_invoice_page_inherit portal_invoice_page_inherit ir.ui.view qweb Inherits account.portal_invoice_page
portal_my_task_inherit portal_my_task_inherit ir.ui.view qweb Inherits project.portal_my_task
portal_my_timesheets_inherit portal_my_timesheets_inherit ir.ui.view qweb Inherits hr_timesheet.portal_my_timesheets
portal_timesheet_table_inherit portal_timesheet_table_inherit ir.ui.view qweb Inherits hr_timesheet.portal_timesheet_table
product_template_view_search_sale_timesheet product.template.search.timesheet product.template search Inherits product.product_template_search_view
project_project_view_form project.project.form.inherit project.project form Inherits hr_timesheet.project_invoice_form
project_project_view_kanban_inherit_sale_timesheet project.project.kanban.inherit.sale.timesheet project.project kanban Inherits hr_timesheet.view_project_kanban_inherited
project_project_view_kanban_inherit_sale_timesheet_so_button project.project.kanban.inherit.sale.timesheet.so.button project.project kanban Inherits project.view_project_kanban
project_sharing_inherit_project_task_view_form project.task.form.inherit.timesheet project.task form Inherits hr_timesheet.project_sharing_inherit_project_task_view_form
project_task_view_form_inherit_sale_timesheet project.task.form.inherit.timesheet project.task form Inherits project.view_task_form2
project_task_view_search_inherit_sale_timesheet project.task.view.search.inherit project.task search Inherits hr_timesheet.project_task_view_search
report_timesheet_account_move report_timesheet_account_move ir.ui.view qweb New
report_timesheet_sale_order report_timesheet_sale_order ir.ui.view qweb New
res_config_settings_view_form res.config.settings.view.form.inherit.sale.timesheet res.config.settings form Inherits hr_timesheet.res_config_settings_view_form
sale_advance_payment_inv_timesheet_view_form sale_timesheet.sale.advance.payment.inv.view.form sale.advance.payment.inv form Inherits sale.view_sale_advance_payment_inv
sale_order_portal_content_inherit sale_order_portal_content_inherit ir.ui.view qweb Inherits sale.sale_order_portal_template
timesheet_sale_page timesheet_sale_page ir.ui.view qweb New
timesheet_view_search account.analytic.line.search account.analytic.line search Inherits hr_timesheet.hr_timesheet_line_search
timesheete_analysis_report_form timesheets.analysis.report.form timesheets.analysis.report form Inherits hr_timesheet.timesheets_analysis_report_form
timesheets_analysis_report_graph_inherit timesheets.analysis.report.graph timesheets.analysis.report graph Inherits hr_timesheet.timesheets_analysis_report_pivot_employee
timesheets_analysis_report_graph_invoice_type timesheets.analysis.report.graph timesheets.analysis.report graph New
timesheets_analysis_report_graph_project_inherit timesheets.analysis.report.graph.project timesheets.analysis.report graph Inherits hr_timesheet.timesheets_analysis_report_graph_project
timesheets_analysis_report_graph_task_inherit timesheets.analysis.report.graph.task timesheets.analysis.report graph Inherits hr_timesheet.timesheets_analysis_report_graph_task
timesheets_analysis_report_graph_timesheet_grid timesheets.analysis.report.graph timesheets.analysis.report graph Inherits hr_timesheet.timesheets_analysis_report_graph_employee
timesheets_analysis_report_list_inherited timesheets.analysis.report.list.inherited timesheets.analysis.report list Inherits hr_timesheet.timesheets_analysis_report_list
timesheets_analysis_report_pivot_inherit timesheets.analysis.report.pivot timesheets.analysis.report pivot Inherits hr_timesheet.timesheets_analysis_report_pivot_employee
timesheets_analysis_report_pivot_invoice_type timesheets.analysis.report.pivot timesheets.analysis.report pivot New
timesheets_analysis_report_pivot_project_inherit timesheets.analysis.report.pivot.project timesheets.analysis.report pivot Inherits hr_timesheet.timesheets_analysis_report_pivot_project
timesheets_analysis_report_pivot_task_inherit timesheets.analysis.report.pivot.task timesheets.analysis.report pivot Inherits hr_timesheet.timesheets_analysis_report_pivot_task
view_calendar_account_analytic_line account.analytic.line.calendar account.analytic.line calendar Inherits hr_timesheet.view_calendar_account_analytic_line
view_calendar_account_analytic_line_multi_create account.analytic.line.calendar.multi_create account.analytic.line calendar Inherits hr_timesheet.view_calendar_account_analytic_line_multi_create
view_hr_timesheet_line_graph_employee_per_date account.analytic.line.graph.employee.per.date account.analytic.line graph New
view_hr_timesheet_line_graph_invoice_employee account.analytic.line.graph.invoice.employee account.analytic.line graph Inherits view_hr_timesheet_line_graph_employee_per_date
view_hr_timesheet_line_pivot_billing_rate account.analytic.line.pivot.billing.rate account.analytic.line pivot New
view_hr_timesheet_line_pivot_inherited account.analytic.line.pivot account.analytic.line pivot Inherits hr_timesheet.view_hr_timesheet_line_pivot
view_order_form_inherit_sale_timesheet sale.order.form.sale.timesheet sale.order form Inherits sale_project.view_order_form_inherit_sale_project
view_product_timesheet_form product.template.timesheet.form product.template form Inherits sale.product_template_form_view
view_task_project_user_fsm_graph_base_inherited report.project.task.user.fsm.graph.base.inherited report.project.task.user graph Inherits project.view_task_project_user_fsm_graph_base
view_task_project_user_fsm_pivot_base_inherited report.project.task.user.fsm.pivot.base.inherited report.project.task.user pivot Inherits project.view_task_project_user_fsm_pivot_base
view_task_project_user_pivot_inherited report.project.task.user.pivot.inherited report.project.task.user pivot Inherits project.view_task_project_user_pivot
view_task_tree2_inherited project.task.list.inherited project.task list Inherits hr_timesheet.view_task_tree2_inherited
HTTP endpoints (2)
Route(s)HandlerAuthTypeMethodsFlags
/my/tasks/<task_id>/orders/invoices, /my/tasks/<task_id>/orders/invoices/page/<int:page> PortalProjectAccount.portal_my_tasks_invoices user http ALL website
(inherited route override) SaleTimesheetCustomerPortal.portal_my_timesheets inherited http ALL
Models touched (16)

New fields (8)
  • allow_billable Boolean
    related='project_id.allow_billable'
  • commercial_partner_id Many2one → res.partner
    compute='_compute_commercial_partner' args: 'res.partner'
  • is_so_line_edited Boolean
    args: 'Is Sales Order Item Manually Edited'
  • order_id Many2one
    index=True readonly=True related='so_line.order_id' store=True
  • sale_order_state Selection
    related='order_id.state'
  • so_line Many2one
    compute='_compute_so_line' domain=_domain_so_line falsy_value_label='Non-billable' help='Sales order item to which the time spent will be added in order to be invoiced to your customer. Remove the sales order item for the timesheet entry to be non-billable.' readonly=False store=True
  • timesheet_invoice_id Many2one → account.move
    copy=False help='Invoice created from the timesheet' index='btree_not_null' readonly=True string='Invoice' args: 'account.move'
  • timesheet_invoice_type Selection
    compute='_compute_timesheet_invoice_type' compute_sudo=True readonly=True store=True string='Billable Type' args: TIMESHEET_INVOICE_TYPES
Public methods (3)
  • action_invoice_from_timesheet(self)
  • action_sale_order_from_timesheet(self)
  • write(self, vals)

New fields (4)
  • timesheet_count Integer
    compute='_compute_timesheet_count' compute_sudo=True export_string_translation=False args: 'Number of timesheets'
  • timesheet_encode_uom_id Many2one → uom.uom
    export_string_translation=False related='company_id.timesheet_encode_uom_id' args: 'uom.uom'
  • timesheet_ids One2many → account.analytic.line
    copy=False export_string_translation=False readonly=True string='Timesheets' args: 'account.analytic.line', 'timesheet_invoice_id'
  • timesheet_total_duration Integer
    compute='_compute_timesheet_total_duration' compute_sudo=True help='Total recorded duration, expressed in the encoding UoM, and rounded to the unit' args: 'Timesheet Total Duration'
Public methods (2)
  • action_post(self)
  • action_view_timesheet(self)

New fields (0)

No new fields.

Public methods (1)
  • unlink(self)

New fields (0)

No new fields.

Public methods (1)
  • reverse_moves(self, is_modify=False)

New fields (0)

No new fields.

Public methods (1)
  • default_get(self, fields)
    @api.model

New fields (0)

No new fields.

Public methods (1)
  • write(self, vals)

New fields (5)
  • project_id Many2one
    domain="['|', ('company_id', '=', False), '&', ('company_id', '=?', company_id), ('company_id', '=', current_company_id), ('allow_billable', '=', True), ('pricing_type', '=', 'task_rate'), ('allow_timesheets', 'in', [service_policy == 'delivered_timesheet', True]), ('is_template', '=', False)]"
  • project_template_id Many2one
    domain="['|', ('company_id', '=', False), '&', ('company_id', '=?', company_id), ('company_id', '=', current_company_id), ('allow_billable', '=', True), ('allow_timesheets', 'in', [service_policy == 'delivered_timesheet', True]), ('is_template', '=', True)]"
  • service_type Selection
    ondelete={'timesheet': 'set manual'} selection_add=[('timesheet', 'Timesheets on project (one fare per SO/Project)')]
  • service_upsell_threshold Float
    default=1 help='Percentage of time delivered compared to the prepaid amount that must be reached for the upselling opportunity activity to be triggered.' args: 'Threshold'
  • service_upsell_threshold_ratio Char
    compute='_compute_service_upsell_threshold_ratio' export_string_translation=False
Public methods (1)
  • write(self, vals)

New fields (7)
  • allocated_hours Float
  • billing_type Selection
    compute='_compute_billing_type' default='not_billable' readonly=False required=True selection=[('not_billable', 'not billable'), ('manually', 'billed manually')] store=True
  • partner_id Many2one
    compute='_compute_partner_id' readonly=False store=True
  • pricing_type Selection
    compute='_compute_pricing_type' default='task_rate' help='The task rate is perfect if you would like to bill different services to different customers at different rates. The fixed rate is perfect if you bill a service at a fixed rate per hour or day worked regardless of the employee who performed it. The employee rate is preferable if your employees deliver the same service at a different rate. For instance, junior and senior consultants would deliver the same service (= consultancy), but at a different rate because of their level of seniority.' search='_search_pricing_type' string='Pricing' args: [('task_rate', 'Task rate'), ('fixed_rate', 'Project rate'), ('employee_rate', 'Employee rate')]
  • sale_line_employee_ids One2many → project.sale.line.employee.map
    copy=False export_string_translation=False help="Sales order item that will be selected by default on the timesheets of the corresponding employee. It bypasses the sales order item defined on the project and the task, and can be modified on each timesheet entry if necessary. In other words, it defines the rate at which an employee's time is billed based on their expertise, skills or experience, for instance.\nIf you would like to bill the same service at a different rate, you need to create two separate sales order items as each sales order item can only have a single unit price at a time.\nYou can also define the hourly company cost of your employees for their timesheets on this project specifically. It will bypass the timesheet cost set on the employee." args: 'project.sale.line.employee.map', 'project_id', 'Sale line/Employee map'
  • timesheet_product_id Many2one → product.product
    check_company=True compute='_compute_timesheet_product_id' default=_default_timesheet_product_id domain="[\n ('type', '=', 'service'),\n ('invoice_policy', '=', 'delivery'),\n ('service_type', '=', 'timesheet'),\n ]" help='Service that will be used by default when invoicing the time spent on a task. It can be modified on each task individually by selecting a specific sales order item.' readonly=False store=True string='Timesheet Product' args: 'product.product'
  • warning_employee_rate Boolean
    compute='_compute_warning_employee_rate' compute_sudo=True export_string_translation=False
Public methods (7)
  • action_billable_time_button(self)
  • action_profitability_items(self, section_name, domain=None, res_id=False)
  • action_project_timesheets(self)
  • action_view_timesheet(self)
  • default_get(self, fields)
    @api.model
    Pre-fill timesheet product as "Time" data product when creating new project allowing billable tasks by default.
  • get_panel_data(self)
  • write(self, vals)

New fields (13)
  • company_id Many2one → res.company
    export_string_translation=False related='project_id.company_id' string='Company' args: 'res.company'
  • cost Monetary
    compute='_compute_cost' currency_field='cost_currency_id' help="This cost overrides the employee's default employee hourly wage in employee's HR Settings" readonly=False store=True
  • cost_currency_id Many2one → res.currency
    export_string_translation=False readonly=True related='employee_id.currency_id' string='Cost Currency' args: 'res.currency'
  • currency_id Many2one → res.currency
    compute='_compute_currency_id' readonly=False store=True string='Currency' args: 'res.currency'
  • display_cost Monetary
    compute='_compute_display_cost' currency_field='cost_currency_id' groups='project.group_project_manager,hr.group_hr_user' inverse='_inverse_display_cost' string='Hourly Cost'
  • employee_id Many2one → hr.employee
    domain="[('id', 'not in', existing_employee_ids)]" required=True args: 'hr.employee', 'Employee'
  • existing_employee_ids Many2many → hr.employee
    compute='_compute_existing_employee_ids' compute_sudo=True export_string_translation=False args: 'hr.employee'
  • is_cost_changed Boolean
    compute='_compute_is_cost_changed' export_string_translation=False store=True args: 'Is Cost Manually Changed'
  • partner_id Many2one
    export_string_translation=False related='project_id.partner_id'
  • price_unit Float
    compute='_compute_price_unit' readonly=True store=True args: 'Unit Price'
  • project_id Many2one → project.project
    domain=[('is_template', '=', False)] index=True required=True args: 'project.project', 'Project'
  • sale_line_id Many2one → sale.order.line
    compute='_compute_sale_line_id' domain=<expr> readonly=False store=True args: 'sale.order.line', 'Sales Order Item'
  • sale_order_id Many2one
    export_string_translation=False related='project_id.sale_order_id'
Public methods (2)
  • create(self, vals_list)
    @api.model_create_multi
  • write(self, vals)

New fields (8)
  • has_multi_sol Boolean
    compute='_compute_has_multi_sol' compute_sudo=True
  • is_project_map_empty Boolean
    compute='_compute_is_project_map_empty' args: 'Is Project map empty'
  • last_sol_of_customer Many2one → sale.order.line
    compute='_compute_last_sol_of_customer' args: 'sale.order.line'
  • pricing_type Selection
    related='project_id.pricing_type'
  • remaining_hours_available Boolean
    related='sale_line_id.remaining_hours_available'
  • remaining_hours_so Float
    compute='_compute_remaining_hours_so' compute_sudo=True search='_search_remaining_hours_so' args: 'Time Remaining on SO'
  • sale_order_id Many2one
    domain="['|', '|', ('partner_id', '=', partner_id), ('partner_id.commercial_partner_id.id', 'parent_of', partner_id), ('partner_id', 'parent_of', partner_id)]"
  • timesheet_product_id Many2one
    related='project_id.timesheet_product_id'
Public methods (1)
  • TASK_PORTAL_READABLE_FIELDS(self)
    @property

New fields (1)
  • remaining_hours_so Float
    groups='hr_timesheet.group_hr_timesheet_user' readonly=True args: 'Time Remaining on SO'
Public methods (0)

No public methods.

New fields (1)
  • invoice_policy Boolean
    help='Timesheets taken when invoicing time spent' string='Invoice Policy'
Public methods (0)

No public methods.

New fields (3)
  • date_end_invoice_timesheet Date
    help='Only timesheets not yet invoiced (and validated, if applicable) from this period will be invoiced. If the period is not indicated, all timesheets not yet invoiced (and validated, if applicable) will be invoiced without distinction.' string='End Date'
  • date_start_invoice_timesheet Date
    help='Only timesheets not yet invoiced (and validated, if applicable) from this period will be invoiced. If the period is not indicated, all timesheets not yet invoiced (and validated, if applicable) will be invoiced without distinction.' string='Start Date'
  • invoicing_timesheet_enabled Boolean
    compute='_compute_invoicing_timesheet_enabled' export_string_translation=False store=True
Public methods (0)

No public methods.

New fields (4)
  • show_hours_recorded_button Boolean
    compute='_compute_show_hours_recorded_button' compute_sudo=True export_string_translation=False groups='hr_timesheet.group_hr_timesheet_user'
  • timesheet_count Float
    compute='_compute_timesheet_count' export_string_translation=False groups='hr_timesheet.group_hr_timesheet_user' string='Timesheet activities'
  • timesheet_encode_uom_id Many2one → uom.uom
    export_string_translation=False related='company_id.timesheet_encode_uom_id' args: 'uom.uom'
  • timesheet_total_duration Integer
    compute='_compute_timesheet_total_duration' compute_sudo=True export_string_translation=False groups='hr_timesheet.group_hr_timesheet_user' help='Total recorded duration, expressed in the encoding UoM, and rounded to the unit' args: 'Timesheet Total Duration'
Public methods (2)
  • action_view_timesheet(self)
  • create(self, vals_list)
    @api.model_create_multi

New fields (6)
  • analytic_line_ids One2many
    domain=[('project_id', '=', False)]
  • has_displayed_warning_upsell Boolean
    copy=False export_string_translation=False args: 'Has Displayed Warning Upsell'
  • qty_delivered_method Selection
    selection_add=[('timesheet', 'Timesheets')]
  • remaining_hours Float
    compute='_compute_remaining_hours' compute_sudo=True store=True args: 'Time Remaining on SO'
  • remaining_hours_available Boolean
    compute='_compute_remaining_hours_available' compute_sudo=True
  • timesheet_ids One2many → account.analytic.line
    domain=[('project_id', '!=', False)] export_string_translation=False string='Timesheets' args: 'account.analytic.line', 'so_line'
Public methods (0)

No public methods.

New fields (8)
  • billable_time Float
    help='Number of hours/days linked to a SOL.' readonly=True args: 'Billable Time'
  • margin Monetary
    currency_field='currency_id' help='Timesheets revenues minus the costs' readonly=True args: 'Margin'
  • non_billable_time Float
    help='Number of hours/days not linked to a SOL.' readonly=True args: 'Non-billable Time'
  • order_id Many2one → sale.order
    readonly=True string='Sales Order' args: 'sale.order'
  • so_line Many2one → sale.order.line
    readonly=True string='Sales Order Item' args: 'sale.order.line'
  • timesheet_invoice_id Many2one → account.move
    help='Invoice created from the timesheet' readonly=True string='Invoice' args: 'account.move'
  • timesheet_invoice_type Selection
    readonly=True string='Billable Type' args: TIMESHEET_INVOICE_TYPES
  • timesheet_revenues Monetary
    currency_field='currency_id' help='Number of hours spent multiplied by the unit price per hour/day.' readonly=True args: 'Timesheet Revenues'
Public methods (0)

No public methods.

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…

Loading…