Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions fieldservice_sale_timesheet_material/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=========================================
Field Service - Sale Timesheet & Material
=========================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:87e70d22046d3920703173709fe35da1f89ef609b22a87cbaf601fdaee96ed70
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Ffield--service-lightgray.png?logo=github
:target: https://github.com/OCA/field-service/tree/16.0/fieldservice_sale_timesheet_material
:alt: OCA/field-service
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/field-service-16-0/field-service-16-0-fieldservice_sale_timesheet_material
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/field-service&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module lets you invoice the **time** spent and the **materials** consumed
on a field service order by adding them as lines to the order's sale order,
which can then be invoiced through the standard sales flow.

It applies to field service orders that were **generated from a sale order**
(see *Field Service - Sale*): the recorded work is pushed back to that same
sale order. It builds on ``fsm.order``:

* timesheets are the ``account.analytic.line`` records linked to the order
(from *Field Service - Analytic Accounting*), grouped by their *Time Type*
product;
* materials are the consumed stock moves of the order (from
*Field Service - Stock*), grouped by product. ``fieldservice_stock`` only
displays these moves read-only, so creating them requires a companion module
such as **Field Service - Stock Request** (``fieldservice_stock_request``),
or deliveries coming from the sale order.

A single **Add to Sale Order** button on the field service order pushes both
timesheets and materials onto the linked sale order. The button is only shown
when the order is linked to a sale order; it never creates one. The operation
is idempotent: only work that has not yet been billed is added.

**Table of contents**

.. contents::
:local:

Usage
=====

#. Start from a confirmed **sale order** that generated a field service order
(see *Field Service - Sale*), and make sure the order's **location** has an
*Analytic Account* set (*Field Service - Analytic Accounting*).
#. On the field service order, record the time spent in the **Timesheets**
tab, choosing a *Time Type* product for each line.
#. Record the materials consumed on site. These are the order's **done
outgoing stock moves**, which *Field Service - Stock* only displays
read-only — so a companion module is required to create them. Install
**Field Service - Stock Request** (``fieldservice_stock_request``) and enter
the products in the **Stock Requests** list of the order's *Inventory* tab,
then process them through that module's flow until the moves reach the
*Done* state. Materials delivered from the sale order appear here too. Only
*Done* moves are billed.
#. Click **Add to Sale Order**. A line is added to the linked sale order for
each *Time Type* product (with the total hours) and for each consumed
product (with the net delivered quantity). The button is hidden when the
order is not linked to a sale order.
#. Open the sale order with the **Sale Order** smart button and create the
invoice as usual.

Clicking **Add to Sale Order** again only adds timesheets and materials that
have not been billed yet, so it is safe to use repeatedly as work progresses.

The **Service Order** report (*Print* menu on the field service order) is
extended with a **Time Spent** section listing each timesheet line with its
total, and a **Materials** section listing the *Done* stock moves per product
and direction (*Used* for outgoing moves, *Returned* for incoming ones), so the
printout shows both what was consumed on site and what came back.

Recommended product configuration:

The **service product on the original sale order** — the one that makes the
sale order generate the field service order — must have *Field Service
Tracking* set to *Per sale order* or *Per sale order line* (see *Field Service
- Sale*). That setting is what creates the field service order on sale
confirmation; without it there is no order to push the work back to.

The **time and material products** added by *Add to Sale Order*:

* *Time Type* products should be **services** measured in hours;
* the *Invoicing Policy* can be *Ordered quantities* or *Delivered
quantities*: the delivered quantity of time lines is set from the recorded
hours, while the delivered quantity of material lines comes from the field
service order's own stock moves (which are linked to the created lines, so
no extra delivery is generated);
* *Field Service Tracking* should be left at *Don't create FSM order*. The
lines this module creates are already linked back to the originating field
service order, so they never spawn further orders; but a *Per sale order
line* setting would switch the line's delivered-quantity method to *Field
Service* and override the quantity computed here.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/field-service/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/field-service/issues/new?body=module:%20fieldservice_sale_timesheet_material%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Innovyou

Contributors
~~~~~~~~~~~~

* Lorenzo Battistini

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/field-service <https://github.com/OCA/field-service/tree/16.0/fieldservice_sale_timesheet_material>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions fieldservice_sale_timesheet_material/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
24 changes: 24 additions & 0 deletions fieldservice_sale_timesheet_material/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (C) 2026 Innovyou
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Field Service - Sale Timesheet & Material",
"summary": "Invoice field service timesheets and consumed materials "
"by adding them to the sale order",
"version": "16.0.1.0.0",
"category": "Field Service",
"author": "Innovyou, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/field-service",
"depends": [
"fieldservice_sale",
"fieldservice_account_analytic",
"fieldservice_stock",
],
"data": [
"views/fsm_order.xml",
"report/fsm_order_report_template.xml",
],
"license": "AGPL-3",
"development_status": "Beta",
"installable": True,
}
145 changes: 145 additions & 0 deletions fieldservice_sale_timesheet_material/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * fieldservice_sale_timesheet_material
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-08 14:12+0000\n"
"PO-Revision-Date: 2026-06-08 14:12+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "<strong>Total</strong>"
msgstr "<strong>Totale</strong>"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.fsm_order_form_sale_timesheet_material
msgid ""
"Add the recorded timesheets and consumed materials as lines on the order's "
"sale order."
msgstr ""
"Aggiunge i fogli ore registrati e i materiali consumati come righe "
"nell'ordine di vendita dell'ordine."

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.fsm_order_form_sale_timesheet_material
msgid "Add to Sale Order"
msgstr "Aggiungi all'ordine di vendita"

#. module: fieldservice_sale_timesheet_material
#: model:ir.model,name:fieldservice_sale_timesheet_material.model_account_analytic_line
msgid "Analytic Line"
msgstr "Riga analitica"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Date"
msgstr "Data"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Description"
msgstr "Descrizione"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Direction"
msgstr "Direzione"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.fsm_order_form_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Duration"
msgstr "Durata"

#. module: fieldservice_sale_timesheet_material
#: model:ir.model.fields,field_description:fieldservice_sale_timesheet_material.field_account_analytic_line__fsm_sale_line_id
#: model:ir.model.fields,field_description:fieldservice_sale_timesheet_material.field_stock_move__fsm_sale_line_id
msgid "FSM Sale Order Line"
msgstr "Riga ordine di vendita FSM"

#. module: fieldservice_sale_timesheet_material
#: model:ir.model,name:fieldservice_sale_timesheet_material.model_fsm_order
msgid "Field Service Order"
msgstr "Ordine assistenza sul campo"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Materials"
msgstr "Materiali"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Product"
msgstr "Prodotto"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Quantity"
msgstr "Quantità"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Returned"
msgstr "Restituito"

#. module: fieldservice_sale_timesheet_material
#: model:ir.model.fields,help:fieldservice_sale_timesheet_material.field_stock_move__fsm_sale_line_id
msgid ""
"Sale order line on which this consumed material has been billed from the "
"field service order."
msgstr ""
"Riga dell'ordine di vendita su cui questo materiale consumato è stato "
"fatturato dall'ordine di assistenza sul campo."

#. module: fieldservice_sale_timesheet_material
#: model:ir.model.fields,help:fieldservice_sale_timesheet_material.field_account_analytic_line__fsm_sale_line_id
msgid "Sale order line on which this field service timesheet has been billed."
msgstr ""
"Riga dell'ordine di vendita su cui questo foglio ore di assistenza sul campo "
"è stato fatturato."

#. module: fieldservice_sale_timesheet_material
#: model:ir.model,name:fieldservice_sale_timesheet_material.model_stock_move
msgid "Stock Move"
msgstr "Movimento di magazzino"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Time Spent"
msgstr "Tempo impiegato"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.fsm_order_form_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Time Type"
msgstr "Tipo di tempo"

#. module: fieldservice_sale_timesheet_material
#: model:ir.model.fields,field_description:fieldservice_sale_timesheet_material.field_fsm_order__timesheet_ids
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.fsm_order_form_sale_timesheet_material
msgid "Timesheets"
msgstr "Fogli ore"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Unit of Measure"
msgstr "Unità di misura"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Used"
msgstr "Utilizzato"

#. module: fieldservice_sale_timesheet_material
#: model_terms:ir.ui.view,arch_db:fieldservice_sale_timesheet_material.report_fsm_order_document_timesheet_material
msgid "Worker"
msgstr "Operatore"
3 changes: 3 additions & 0 deletions fieldservice_sale_timesheet_material/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import account_analytic_line
from . import stock_move
from . import fsm_order
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (C) 2026 Innovyou
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"

fsm_sale_line_id = fields.Many2one(
"sale.order.line",
string="FSM Sale Order Line",
copy=False,
index=True,
help="Sale order line on which this field service timesheet has been "
"billed.",
)
Loading
Loading