diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst new file mode 100644 index 0000000000..7056fd7ee0 --- /dev/null +++ b/fieldservice_sale/README.rst @@ -0,0 +1,162 @@ +===================== +Field Service - Sales +===================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-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 + :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 + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/field-service&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +The module integrates the Field Service application with the Sales one and +allows you to sell products that generate field service orders. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +To install Field Service and have the mapping features, you need to install GeoEngine. + +Please refer to the installation instructions available at: +https://github.com/OCA/geospatial/tree/13.0/base_geoengine + +Configuration +============= + +Products must be configured properly in order to create field service +orders upon sale order confirmation. + +The field service tracking of a product defines how it generates a field service +order if the product is sold via sale order. + +To configure a product that generates a unique field service order on each +sale order line: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Field Service Tracking to 'One FSM Order per Sale Order Line' +* Select the FSM Order Template that will be used for creating FSM Orders when + a Sale Order is confirmed with this product + +To configure a product that generates a unique field service order for +an individual sale order: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Field Service Tracking to 'One FSM Order per Sale Order' +* Select the FSM Order Template that will be used for creating FSM Orders when + a Sale Order is confirmed with this product + +To setup a sales territory: + +* Go to Field Service > Master Data > Locations +* Create or select a location +* Go to the Sales tab and select the sales territory + +Usage +===== + +* Go to Sales +* Create a new Quotation/Sale Order +* Set the FSM Location to be used +* On a Sale Order Line, select a product configured for field service orders +* Confirm the Sale Order +* Field Service orders linked to SO lines are created +* When a Field Service order is completed, the quantity delivered for its + linked sale order line will be updated to the quantity ordered, indicating + this line is ready for invoicing. + +Known issues / Roadmap +====================== + +* Provide a mapping between an address and the branch and use it to set the + pricelist of a new partner + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Open Source Integrators + +Contributors +~~~~~~~~~~~~ + +* Open Source Integrators + + * Steve Campbell + * Maxime Chambreuil + * Wolfgang Hall + * Raphael Lee + +* Serpent Consulting Services Pvt. Ltd. +* Brian McMaster +* Rapha??l Reverdy +* Cl??ment Mombereau + +* `Tecnativa `_: + + * Stefan Ungureanu + +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. + +.. |maintainer-wolfhall| image:: https://github.com/wolfhall.png?size=40px + :target: https://github.com/wolfhall + :alt: wolfhall +.. |maintainer-max3903| image:: https://github.com/max3903.png?size=40px + :target: https://github.com/max3903 + :alt: max3903 +.. |maintainer-brian10048| image:: https://github.com/brian10048.png?size=40px + :target: https://github.com/brian10048 + :alt: brian10048 + +Current `maintainers `__: + +|maintainer-wolfhall| |maintainer-max3903| |maintainer-brian10048| + +This module is part of the `OCA/field-service `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/fieldservice_sale/__init__.py b/fieldservice_sale/__init__.py new file mode 100644 index 0000000000..66ca882fcc --- /dev/null +++ b/fieldservice_sale/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2018 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py new file mode 100644 index 0000000000..f5d3759ad0 --- /dev/null +++ b/fieldservice_sale/__manifest__.py @@ -0,0 +1,31 @@ +# Copyright (C) 2018 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Field Service - Sales", + "version": "16.0.1.0.0", + "summary": "Sell field services.", + "category": "Field Service", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/field-service", + "depends": [ + "fieldservice", + "sale_management", + "fieldservice_account", + ], + "data": [ + "security/ir.model.access.csv", + "security/res_groups.xml", + "views/fsm_location.xml", + "views/fsm_order.xml", + "views/product_template.xml", + "views/sale_order.xml", + ], + "license": "AGPL-3", + "development_status": "Beta", + "maintainers": [ + "wolfhall", + "max3903", + "brian10048", + ], + "installable": True, +} diff --git a/fieldservice_sale/i18n/de.po b/fieldservice_sale/i18n/de.po new file mode 100644 index 0000000000..c321aaea5f --- /dev/null +++ b/fieldservice_sale/i18n/de.po @@ -0,0 +1,279 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-12-04 15:44+0000\n" +"Last-Translator: Nils Coenen | NICO SOLUTIONS - ENGINEERING & IT \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Verkaufsauftrag" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"Je nach Produktkonfiguration kann die gelieferte Menge automatisch nach " +"Mechanismus berechnet werden :\n" +" - Manuell: Die Menge wird manuell auf der Zeile eingestellt\n" +" - Analytisch aus Ausgaben: Die Menge ist die Mengensumme aus gebuchten " +"Ausgaben\n" +" - Zeiterfassung: Die Menge ist die Summe der Stunden, die für Aufgaben " +"erfasst wurden, die mit dieser Verkaufszeile verknüpft sind\n" +" - Lagerbewegungen: Die Menge stammt aus bestätigten Entnahmen\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Erstellen Sie einen FSM-Auftrag pro Verkaufsauftrag" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Erstellen Sie einen FSM-Auftrag pro Verkaufsauftragsposition" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Legt fest, was bei Auftragsbestätigung passiert:\n" +" - Nichts: nichts Zusätzliches, Standardverhalten.\n" +" - Pro Verkaufsauftrag: Für den Verkauf wird ein FSM-Auftrag " +"erstellt.\n" +" - Pro Verkaufsauftragszeile: Ein FSM-Auftrag für jede " +"Verkaufsauftragszeile\n" +" wird erstellt." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "Keinen FSM-Auftrag erstellen" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "FSM-Standort muss festgelegt werden" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Field-Service-Aufträge" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Field-Service-Auftrag" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Field-Service-Auftragsvorlage" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "Von der Verkaufsauftragsposition generierter Field Service-Auftrag" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Field-Service-Aufträge" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Field Service Verfolgung" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Field Service Aufträge, die diesem Verkauf zugeordnet sind" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Bestellmenge manuell einstellen: Rechnung auf Basis der manuell eingegebenen " +"Menge, ohne Erstellung eines Analysekontos.\n" +"Stundenzettel im Vertrag: Rechnung basierend auf den nachverfolgten Stunden " +"auf dem zugehörigen Stundenzettel.\n" +"Erstellen Sie eine Aufgabe und verfolgen Sie die Stunden: Erstellen Sie eine " +"Aufgabe zur Auftragsvalidierung und verfolgen Sie die Arbeitsstunden." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "Methode zum Aktualisieren der gelieferten Menge" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Auftrag" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Produktvorlage" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "" +"Verkaufsauftrgspositonen, die einen FSM-Auftrag generieren, gelten für " +"diesen Standort" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Verkauf" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Auftragszeile" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Verkauf" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "Verkaufsauftrag" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Auftragszeile" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Verkaufsaufträge" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Wählen Sie die zu erstellende Field Service Auftragsvorlage aus" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Service-Ort" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Service nachverfolgen" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created ({}): {}\n" +#~ " " +#~ msgstr "" +#~ "Field Service Auftrag erstellt ({}): {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: {}\n" +#~ " " +#~ msgstr "" +#~ "Field Service Auftrag erstellt: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {}\n" +#~ " " +#~ msgstr "" +#~ "Dieser Auftrag wurde erstellt aus: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {} ({})\n" +#~ " " +#~ msgstr "" +#~ "Dieser Auftrag wurde erstellt aus: {} ({})\n" +#~ " " + +#~ msgid "Create a recurring order" +#~ msgstr "Wiederkehrenden Auftrag erstellen" + +#~ msgid "Field Service Location" +#~ msgstr "Field-Service-Ort" + +#~ msgid "Sale Order" +#~ msgstr "Verkaufsauftrag" + +#~ msgid "Stock Moves" +#~ msgstr "Lagerbewegungen" + +#~ msgid "Create a single order" +#~ msgstr "Auftrag erstellen" + +#~ msgid "Field Service Information" +#~ msgstr "Field-Service-Informationen" + +#~ msgid "Requested Service Date" +#~ msgstr "Gew??nschter Service-Termin" diff --git a/fieldservice_sale/i18n/es.po b/fieldservice_sale/i18n/es.po new file mode 100644 index 0000000000..8fe7c1b83d --- /dev/null +++ b/fieldservice_sale/i18n/es.po @@ -0,0 +1,301 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-02 20:22+0000\n" +"Last-Translator: Leonardo J. Caballero G. \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Pedido de Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"Según la configuración del producto, la cantidad entregada se puede calcular " +"automáticamente por mecanismo:\n" +" - Manual: la cantidad se establece manualmente en la línea\n" +" - Analítica de gastos: la cantidad es la suma de la cantidad de gastos " +"contabilizados\n" +" - Hoja de tiempo: la cantidad es la suma de horas registradas en tareas " +"vinculadas a esta línea de venta\n" +" - Movimientos de stock: la cantidad proviene de pickings confirmados\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Crear un pedido FSM por pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Crear un pedido FSM por línea de pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Determina qué sucede con la confirmación del pedido de venta:\n" +" - Ninguno: nada adicional, comportamiento predeterminado.\n" +" - Por orden de venta: se creará una orden FSM para la venta." +"\n" +" - Por línea de pedido de venta: un pedido FSM por cada línea " +"de pedido de venta\n" +" se creará." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "No cree un pedido FSM" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "Se debe establecer la ubicación FSM" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Pedidos FSM" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Orden de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Plantilla de orden de servicio de campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "" +"Pedido de servicio de campo generado por el artículo de pedido de ventas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "Órdenes de servicio de campo creadas: %s" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Órdenes de servicio de campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Servicio de Seguimiento de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Pedidos de servicio de campo asociados a esta venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Establecer cantidades manualmente en el pedido: Factura basada en la " +"cantidad ingresada manualmente, sin crear una cuenta analítica.\n" +"Hojas de tiempo en el contrato: Factura basada en las horas rastreadas en la " +"hoja de tiempo relacionada.\n" +"Crear una tarea y realizar un seguimiento de las horas: cree una tarea en la " +"validación de pedidos de ventas y realice un seguimiento de las horas de " +"trabajo." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "Método para actualizar la cantidad entregada" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Pedido" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Plantilla de Producto" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "Las líneas SO que generan un pedido FSM serán para esta ubicación" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Línea de Venta" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Ventas" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "Pedidos de Venta" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de Pedido de Ventas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Pedidos de Ventas" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Seleccione la plantilla de pedido de servicio de campo que se creará" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Ubicación de Servicio" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Servicio de Seguimiento" + +#~ msgid "Analytic From Expenses" +#~ msgstr "Anal??tica desde Gastos" + +#~ msgid "Create a recurring order" +#~ msgstr "Crear orden recurrente" + +#~ msgid "Field Service Location" +#~ msgstr "Ubicaci??n del Servicio de Campo" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created (%s): %s\n" +#~ " " +#~ msgstr "" +#~ "Orden de Servicio de Campo Creada (%s): %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: %s\n" +#~ " " +#~ msgstr "" +#~ "Orden de Servicio de Campo Creada: %s\n" +#~ " " + +#~ msgid "Manual" +#~ msgstr "Manual" + +#~ msgid "Manually set quantities on order" +#~ msgstr "Establecer cantidades manualmente en orden" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de Venta" + +#~ msgid "Sales Territory" +#~ msgstr "Territorio de Ventas" + +#~ msgid "Stock Moves" +#~ msgstr "Movimientos de Inventario" + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado a partir de: %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s (%s)\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado a partir de: %s (%s)\n" +#~ " " + +#~ msgid "Timesheets" +#~ msgstr "Hojas de Tiempo" + +#~ msgid "Timesheets on project (one fare per SO/Project)" +#~ msgstr "Hojas de tiempo en el proyecto (una tarifa por SO / Proyecto)" + +#~ msgid "branch" +#~ msgstr "sucursal" + +#~ msgid "Is a Field Service" +#~ msgstr "Es un Servicio de Campo" + +#~ msgid "" +#~ "Sales Order item should generate an Order and/or\n" +#~ " Order Recurrence, depending on the product settings." +#~ msgstr "" +#~ "El art??culo de pedido de ventas debe generar un pedido y / o\n" +#~ " Repetici??n de pedidos, seg??n la configuraci??n del " +#~ "producto." diff --git a/fieldservice_sale/i18n/es_AR.po b/fieldservice_sale/i18n/es_AR.po new file mode 100644 index 0000000000..21bbb72157 --- /dev/null +++ b/fieldservice_sale/i18n/es_AR.po @@ -0,0 +1,308 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-04 17:23+0000\n" +"Last-Translator: Ignacio Buioli \n" +"Language-Team: none\n" +"Language: es_AR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Pedido de Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"Según la configuración del producto, la cantidad entregada se puede calcular " +"automáticamente mediante un mecanismo:\n" +" - Manual: la cantidad se establece manualmente en la línea\n" +" - Analítica de gastos: la cantidad es la suma de la cantidad de los " +"gastos contabilizados.\n" +" - Hoja de horas: la cantidad es la suma de horas registradas en tareas " +"vinculadas a esta línea de venta\n" +" - Stock Moves: la cantidad proviene de pickings confirmados\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Crea un pedido FSM por pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Crea un pedido FSM por línea de pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Determina qué sucede tras la confirmación del pedido de venta:\n" +" - Ninguno: nada adicional, comportamiento predeterminado.\n" +" - Por orden de venta: se creará un pedido de FSM para la " +"venta.\n" +" - Por línea de orden de venta: un pedido de FSM para cada " +"línea de pedido de venta\n" +" se creará." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "No crea pedido FSM" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "Ubicación FSM debe estar configurada" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Pedidos FSM" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Pedido de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Plantilla del Pedido de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "" +"Pedido de Servicio de Campo generado por el artículo de Pedido de Ventas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "Pedido(s) de Servicio de Campo Creado(s): %s" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Pedidos de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Rastreo de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Pedidos de servicio de campo asociados a esta venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Cantidad establecida manualmente en el pedido: Factura basada en la cantidad " +"ingresada manualmente, sin crear una cuenta analítica.\n" +"Hojas de tiempo en el contrato: Factura basada en las horas registradas en " +"la hoja de tiempo relacionada.\n" +"Crea una tarea y realiza un seguimiento de las horas: Crea una tarea en la " +"validación de la orden de venta y realiza un seguimiento de las horas de " +"trabajo." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "Método para actualizar las cantidades entregadas" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Pedido" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Plantilla del Producto" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "" +"Las líneas de Pedidos de Venta que generan una orden FSM serán para esta " +"ubicación" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Línea de Venta" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Ventas" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "Pedidos de Venta" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de Pedido de Venta" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Pedidos de Ventas" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Seleccione la plantilla de pedido de servicio de campo que se creará" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Ubicación de Servicio" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Rastrear Servicio" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created ({}): {}\n" +#~ " " +#~ msgstr "" +#~ "Pedido de Servicio de Campo Creado ({}): {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: {}\n" +#~ " " +#~ msgstr "" +#~ "Pedido de Servicio de Campo Creado: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {}\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado desde: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {} ({})\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado: {} ({})\n" +#~ " " + +#~ msgid "Display Name" +#~ msgstr "Mostrar Nombre" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created (%s): %s\n" +#~ " " +#~ msgstr "" +#~ "Pedido de Servicio de Campo Creado (%s): %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: %s\n" +#~ " " +#~ msgstr "" +#~ "Pedido de Servicio de Campo Creado: %s\n" +#~ " " + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Última Modificación el" + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s\n" +#~ " " +#~ msgstr "" +#~ "Este pedido fue creado desde: %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s (%s)\n" +#~ " " +#~ msgstr "" +#~ "Este pedido fue creado desde: %s (%s)\n" +#~ " " diff --git a/fieldservice_sale/i18n/es_CL.po b/fieldservice_sale/i18n/es_CL.po new file mode 100644 index 0000000000..ba294c64c9 --- /dev/null +++ b/fieldservice_sale/i18n/es_CL.po @@ -0,0 +1,308 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-02 20:22+0000\n" +"Last-Translator: Leonardo J. Caballero G. \n" +"Language-Team: none\n" +"Language: es_CL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Pedido de Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"Según la configuración del producto, la cantidad entregada se puede calcular " +"automáticamente por mecanismo:\n" +" - Manual: la cantidad se establece manualmente en la línea\n" +" - Analítica de gastos: la cantidad es la suma de la cantidad de gastos " +"contabilizados\n" +" - Hoja de tiempo: la cantidad es la suma de horas registradas en tareas " +"vinculadas a esta línea de venta\n" +" - Movimientos de stock: la cantidad proviene de pickings confirmados\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Crear un pedido FSM por pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Crear un pedido FSM por línea de pedido de venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Determina qué sucede con la confirmación del pedido de venta:\n" +" - Ninguno: nada adicional, comportamiento predeterminado.\n" +" - Por orden de venta: se creará una orden FSM para la venta." +"\n" +" - Por línea de pedido de venta: un pedido FSM por cada línea " +"de pedido de venta\n" +" se creará." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "No cree un pedido FSM" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "Se debe establecer la ubicación FSM" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Pedidos FSM" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Orden de Servicio de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Plantilla de orden de servicio de campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "" +"Pedido de servicio de campo generado por el artículo de pedido de ventas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "Órdenes de servicio de campo creadas: %s" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Órdenes de servicio de campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Servicio de Seguimiento de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Pedidos de servicio de campo asociados a esta venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Establecer cantidades manualmente en el pedido: Factura basada en la " +"cantidad ingresada manualmente, sin crear una cuenta analítica.\n" +"Hojas de tiempo en el contrato: Factura basada en las horas rastreadas en la " +"hoja de tiempo relacionada.\n" +"Crear una tarea y realizar un seguimiento de las horas: cree una tarea en la " +"validación de pedidos de ventas y realice un seguimiento de las horas de " +"trabajo." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "Método para actualizar la cantidad entregada" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Pedido" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Plantilla de Producto" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "Las líneas SO que generan un pedido FSM serán para esta ubicación" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Venta" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Línea de Venta" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Ventas" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "Pedidos de Venta" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de Pedido de Ventas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Pedidos de Ventas" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Seleccione la plantilla de pedido de servicio de campo que se creará" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Ubicación de Servicio" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Servicio de Seguimiento" + +#~ msgid "Analytic From Expenses" +#~ msgstr "Anal??tica desde Gastos" + +#~ msgid "Create a recurring order" +#~ msgstr "Crear orden recurrente" + +#~ msgid "Default Pricelist" +#~ msgstr "Tarifa Predeterminada" + +#~ msgid "Default pricelist for new customers of this branch." +#~ msgstr "" +#~ "Lista de precios predeterminada para nuevos clientes de esta sucursal." + +#~ msgid "Field Service Location" +#~ msgstr "Ubicaci??n del Servicio de Campo" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created (%s): %s\n" +#~ " " +#~ msgstr "" +#~ "Orden de servicio de campo creada (%s): %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: %s\n" +#~ " " +#~ msgstr "" +#~ "Orden de servicio de campo creada: %s\n" +#~ " " + +#~ msgid "Manual" +#~ msgstr "Manual" + +#~ msgid "Manually set quantities on order" +#~ msgstr "Establecer cantidades manualmente en orden" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de Venta" + +#~ msgid "Sales Territory" +#~ msgstr "Territorio de Ventas" + +#~ msgid "Stock Moves" +#~ msgstr "Movimientos de Inventario" + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado a partir de: %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s (%s)\n" +#~ " " +#~ msgstr "" +#~ "Este pedido ha sido creado a partir de: %s (%s)\n" +#~ " " + +#~ msgid "Timesheets" +#~ msgstr "Hojas de Tiempo" + +#~ msgid "Timesheets on project (one fare per SO/Project)" +#~ msgstr "Hojas de tiempo en el proyecto (una tarifa por SO / Proyecto)" + +#~ msgid "branch" +#~ msgstr "sucursal" + +#~ msgid "Is a Field Service" +#~ msgstr "Es un Servicio de Campo" + +#~ msgid "" +#~ "Sales Order item should generate an Order and/or\n" +#~ " Order Recurrence, depending on the product settings." +#~ msgstr "" +#~ "El art??culo de pedido de ventas debe generar un pedido y / o\n" +#~ " Repetici??n de pedidos, seg??n la configuraci??n del " +#~ "producto." diff --git a/fieldservice_sale/i18n/fieldservice_sale.pot b/fieldservice_sale/i18n/fieldservice_sale.pot new file mode 100644 index 0000000000..c377482998 --- /dev/null +++ b/fieldservice_sale/i18n/fieldservice_sale.pot @@ -0,0 +1,183 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \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 +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order line\n" +" will be created." +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation and track the work hours." +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "" diff --git a/fieldservice_sale/i18n/it.po b/fieldservice_sale/i18n/it.po new file mode 100644 index 0000000000..5ea52e7c17 --- /dev/null +++ b/fieldservice_sale/i18n/it.po @@ -0,0 +1,254 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-05-03 15:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Ordine di vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"In accordo con la configurazione prodotto, la quantità consegnata può essere " +"calcolata automaticamente dal metodo :\n" +" - Manuale: la quantità è impostata manualmente sulla riga\n" +" - Analitica dalle spese: è la somma delle quantità delle spese inserite\n" +" - Foglio ore: la quantità è la somma delle ore registrate sulle attività " +"collegate a questa riga di vendita\n" +" - Movimenti di magazzino: la quantità deriva dai prelievi confermati\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Crea un ordine FSM per ogni ordine di vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Crea un ordine FSM per ogni riga ordine di vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Determina cosa succede alla conferma di un ordine di vendita:\n" +" - Niente: niente in aggiunta, comportamento predefinito.\n" +" - Per ordine di vendita: verrà creato un ordine FSM per la " +"vendita.\n" +" - Per riga ordine di vendita: verrà creato un ordine FSM per " +"ogni\n" +" riga ordine di vendita." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "Non creare ordine FSM" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "La località FSM deve essere impostata" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Ordini FSM" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Ordini assistenza sul campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Modello ordine assistenza sul campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "Ordine assistenza sul campo generato da un elemento ordine di vendita" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "Ordine(i) assistenza sul campo creato(i): %s" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Ordini assistenza sul campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Tracciamento assistenza sul campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Ordini assistenza sul campo associati a questa vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Imposta manualmente la quantità nell'ordine: la fattura si basa sulle " +"quantità inserite manualmente, senza la creazione di un conto analitico.\n" +"Fogli ore a contratto: la fattura si basa sulle ore registrate del relativo " +"foglio ore.\n" +"Crea una attività e traccia le ore: crea una attività alla validazione " +"dell'ordine di vendita e traccia le ore lavorate." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "Metodo di aggiornamento della quantità consegnata" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Ordine" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Modello prodotto" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "Righe ordine vendita che generano un ordine FSM per questa località" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Riga vendita" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Vendite" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Ordini di vendita" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Selezionare il modello ordine assistenza sul campo da creare" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Località servizio" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Traccia servizio" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created ({}): {}\n" +#~ " " +#~ msgstr "" +#~ "Creato ordine assistenza sul campo ({}): {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: {}\n" +#~ " " +#~ msgstr "" +#~ "Creato ordine assistenza sul campo: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {}\n" +#~ " " +#~ msgstr "" +#~ "Questo ordine è stato creato da: {}\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: {} ({})\n" +#~ " " +#~ msgstr "" +#~ "Questo ordine è stato creato da: {} ({})\n" +#~ " " diff --git a/fieldservice_sale/i18n/pt_BR.po b/fieldservice_sale/i18n/pt_BR.po new file mode 100644 index 0000000000..aa908f1e9b --- /dev/null +++ b/fieldservice_sale/i18n/pt_BR.po @@ -0,0 +1,298 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * fieldservice_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-12-08 22:39+0000\n" +"Last-Translator: marcos-mendez \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_fsm_order_form_inherit_sale +msgid "Sale Order" +msgstr "Pedido de Venda" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "" +"According to product configuration, the delivered quantity can be " +"automatically computed by mechanism :\n" +" - Manual: the quantity is set manually on the line\n" +" - Analytic From expenses: the quantity is the quantity sum from posted " +"expenses\n" +" - Timesheet: the quantity is the sum of hours recorded on tasks linked to " +"this sale line\n" +" - Stock Moves: the quantity comes from confirmed pickings\n" +msgstr "" +"De acordo com a configura????o do produto, a quantidade entregue pode ser " +"calculada automaticamente pelo mecanismo:\n" +" - Manual: a quantidade ?? definida manualmente na linha\n" +" - Anal??tico de despesas: a quantidade ?? a soma da quantidade das " +"despesas lan??adas\n" +" - Quadro de hor??rios: a quantidade ?? a soma das horas registradas nas " +"tarefas vinculadas a esta linha de venda\n" +" - Movimenta????o de estoque: a quantidade ?? proveniente das coletas " +"confirmadas\n" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__sale +msgid "Create one FSM order per sale order" +msgstr "Crie um pedido FSM por pedido de venda" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__line +msgid "Create one FSM order per sale order line" +msgstr "Crie um pedido FSM por linha do pedido de venda" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__field_service_tracking +msgid "" +"Determines what happens upon sale order confirmation:\n" +" - None: nothing additional, default behavior.\n" +" - Per Sale Order: One FSM Order will be created for the " +"sale.\n" +" - Per Sale Order Line: One FSM Order for each sale order " +"line\n" +" will be created." +msgstr "" +"Determina o que acontece após a confirmação do pedido de venda:\n" +" - Nenhum: nada adicional, comportamento padrão.\n" +" - Por pedido de venda: um pedido do FSM ser?? criado para a " +"venda.\n" +" - Por linha de pedido de venda: um pedido do FSM para cada " +"linha de pedido de venda.\n" +" Será criado." + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__field_service_tracking__no +msgid "Don't create FSM order" +msgstr "N??o crie ordem FSM" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "FSM Location must be set" +msgstr "Localiza????o do FSM deve ser definida" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_count +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.view_order_form_inherit_sale_fieldservice +msgid "FSM Orders" +msgstr "Ordens do FSM (Field Service Management)" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_fsm_order +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__sale_order_line__qty_delivered_method__field_service +msgid "Field Service Order" +msgstr "Ordem de Servi??o de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Field Service Order Template" +msgstr "Modelo de Ordem de Servi??o de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Field Service Order generated by the sales order item" +msgstr "Ordem de Servi??o de Campo gerada pelo item de pedido de vendas" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/sale_order.py:0 +#, python-format +msgid "Field Service Order(s) Created: %s" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field +msgid "Field Service Orders" +msgstr "Ordens de Servi??o de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__field_service_tracking +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__field_service_tracking +msgid "Field Service Tracking" +msgstr "Rastreamento de Servi??os de Campo" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_order_ids +msgid "Field Service orders associated to this sale" +msgstr "Ordens de Servi??o de Campo associadas a esta venda" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__service_type +msgid "" +"Manually set quantities on order: Invoice based on the manually entered " +"quantity, without creating an analytic account.\n" +"Timesheets on contract: Invoice based on the tracked hours on the related " +"timesheet.\n" +"Create a task and track hours: Create a task on the sales order validation " +"and track the work hours." +msgstr "" +"Definir quantidades manualmente no pedido: fatura com base na quantidade " +"inserida manualmente, sem criar uma conta anal??tica.\n" +"Quadros de hor??rios do contrato: fatura com base nas horas rastreadas no " +"quadro de hor??rios relacionado.\n" +"Crie uma tarefa e acompanhe o hor??rio: crie uma tarefa na valida????o do " +"pedido de vendas e acompanhe o hor??rio de trabalho." + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__qty_delivered_method +msgid "Method to update delivered qty" +msgstr "M??todo para atualizar qtd. entregue" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id +msgid "Order" +msgstr "Ordem" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_product_template +msgid "Product Template" +msgstr "Modelo de Produto" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_sale_order__fsm_location_id +msgid "SO Lines generating a FSM order will be for this location" +msgstr "Linhas SO que geram um pedido FSM ser??o para este local" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_id +msgid "Sale" +msgstr "Venda" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__sale_line_id +msgid "Sale Line" +msgstr "Linha de Venda" + +#. module: fieldservice_sale +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" +msgstr "Vendas" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: fieldservice_sale +#: model:ir.model,name:fieldservice_sale.model_sale_order_line +msgid "Sales Order Line" +msgstr "Linha de Pedidos de Venda" + +#. module: fieldservice_sale +#: code:addons/fieldservice_sale/models/fsm_order.py:0 +#, python-format +msgid "Sales Orders" +msgstr "Pedidos de Vendas" + +#. module: fieldservice_sale +#: model:ir.model.fields,help:fieldservice_sale.field_product_product__fsm_order_template_id +#: model:ir.model.fields,help:fieldservice_sale.field_product_template__fsm_order_template_id +msgid "Select the field service order template to be created" +msgstr "Selecione o modelo de ordem de servi??o de campo a ser criado" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__fsm_location_id +msgid "Service Location" +msgstr "Local do Servi??o" + +#. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_product__service_type +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__service_type +msgid "Track Service" +msgstr "Rastrear Servi??o" + +#~ msgid "Analytic From Expenses" +#~ msgstr "Anal??tico de despesas" + +#~ msgid "Create a recurring order" +#~ msgstr "Crie uma ordem recorrente" + +#~ msgid "Default Pricelist" +#~ msgstr "Lista de pre??os padr??o" + +#~ msgid "Default pricelist for new customers of this branch." +#~ msgstr "Lista de pre??os padr??o para novos clientes desta filial." + +#~ msgid "Field Service Location" +#~ msgstr "Localiza????o do Servi??o de Campo" + +#, python-format +#~ msgid "" +#~ "Field Service Order Created (%s): %s\n" +#~ " " +#~ msgstr "" +#~ "Ordem de Serviço de Campo Criada (%s): %s\n" +#~ " " + +#, python-format +#~ msgid "" +#~ "Field Service Order Created: %s\n" +#~ " " +#~ msgstr "" +#~ "Ordem de serviço de campo criada: %s \n" +#~ " " + +#~ msgid "Manual" +#~ msgstr "Manual" + +#~ msgid "Manually set quantities on order" +#~ msgstr "Definir manualmente quantidades em ordem" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de Venda" + +#~ msgid "Sales Territory" +#~ msgstr "Territ??rio de Vendas" + +#~ msgid "Stock Moves" +#~ msgstr "Movimentos de Estoque" + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s\n" +#~ " " +#~ msgstr "" +#~ "Este pedido foi criado a partir de: %s \n" +#~ " " + +#, python-format +#~ msgid "" +#~ "This order has been created from: %s (%s)\n" +#~ " " +#~ msgstr "" +#~ "Este pedido foi criado a partir de: %s (%s)\n" +#~ " " + +#~ msgid "Timesheets" +#~ msgstr "Planilha de Hor??rios" + +#~ msgid "Timesheets on project (one fare per SO/Project)" +#~ msgstr "Planilhas de tempo no projeto (uma tarifa por OS/Projeto)" + +#~ msgid "branch" +#~ msgstr "Filial" diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py new file mode 100644 index 0000000000..dad9bb704f --- /dev/null +++ b/fieldservice_sale/models/__init__.py @@ -0,0 +1,9 @@ +# Copyright (C) 2018 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import ( + fsm_order, + product_template, + sale_order_line, + sale_order, +) diff --git a/fieldservice_sale/models/fsm_order.py b/fieldservice_sale/models/fsm_order.py new file mode 100644 index 0000000000..b9dbcaaf1c --- /dev/null +++ b/fieldservice_sale/models/fsm_order.py @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Brian McMaster +# Copyright (C) 2019 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import _, fields, models + + +class FSMOrder(models.Model): + _inherit = "fsm.order" + + sale_id = fields.Many2one("sale.order") + sale_line_id = fields.Many2one("sale.order.line") + + def action_view_sales(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "res_model": "sale.order", + "views": [[False, "form"]], + "res_id": self.sale_line_id.order_id.id or self.sale_id.id, + "context": {"create": False}, + "name": _("Sales Orders"), + } diff --git a/fieldservice_sale/models/product_template.py b/fieldservice_sale/models/product_template.py new file mode 100644 index 0000000000..5743184aa9 --- /dev/null +++ b/fieldservice_sale/models/product_template.py @@ -0,0 +1,37 @@ +# Copyright (C) 2019 Brian McMaster +# Copyright (C) 2019 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + service_type = fields.Selection( + selection_add=[("field", "Field Service Orders")], + ondelete={"field": "cascade"}, + ) + field_service_tracking = fields.Selection( + [ + ("no", "Don't create FSM order"), + ("sale", "Create one FSM order per sale order"), + ("line", "Create one FSM order per sale order line"), + ], + default="no", + help="""Determines what happens upon sale order confirmation: + - None: nothing additional, default behavior. + - Per Sale Order: One FSM Order will be created for the sale. + - Per Sale Order Line: One FSM Order for each sale order line + will be created.""", + ) + fsm_order_template_id = fields.Many2one( + "fsm.template", + "Field Service Order Template", + help="Select the field service order template to be created", + ) + + @api.onchange("field_service_tracking") + def _onchange_field_service_tracking(self): + if self.field_service_tracking == "no": + self.fsm_order_template_id = False diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py new file mode 100644 index 0000000000..10783cf2f9 --- /dev/null +++ b/fieldservice_sale/models/sale_order.py @@ -0,0 +1,178 @@ +# Copyright (C) 2019 Brian McMaster +# Copyright (C) 2019 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + fsm_location_id = fields.Many2one( + "fsm.location", + string="Service Location", + help="SO Lines generating a FSM order will be for this location", + compute="_compute_fsm_location_id", + precompute=True, + store=True, + readonly=False, + ) + fsm_order_ids = fields.Many2many( + "fsm.order", + compute="_compute_fsm_order_ids", + string="Field Service orders associated to this sale", + ) + fsm_order_count = fields.Integer( + string="FSM Orders", compute="_compute_fsm_order_ids" + ) + + @api.depends("order_line") + def _compute_fsm_order_ids(self): + for sale in self: + fsm = self.env["fsm.order"].search( + [ + "|", + ("sale_id", "=", sale.id), + ("sale_line_id", "in", sale.order_line.ids), + ] + ) + sale.fsm_order_ids = fsm + sale.fsm_order_count = len(sale.fsm_order_ids) + + @api.depends("partner_id", "partner_shipping_id") + def _compute_fsm_location_id(self): + """ + Autofill the Sale Order's FS location with the partner_id, + the partner_shipping_id or the partner_id.commercial_partner_id if + they are FS locations. + """ + for so in self: + if so.partner_id.fsm_location: + domain = [("partner_id", "=", so.partner_id.id)] + else: + domain = [ + "|", + "|", + ("partner_id", "=", so.partner_id.id), + ("partner_id", "=", so.partner_shipping_id.id), + ("partner_id", "=", so.partner_id.commercial_partner_id.id), + ] + so.fsm_location_id = self.env["fsm.location"].search(domain, limit=1) + + def _prepare_fsm_values(self, **kwargs): + self.ensure_one() + template_id = kwargs.get("template_id", False) + template_ids = kwargs.get("template_ids", [template_id]) + templates = self.env["fsm.template"].search([("id", "in", template_ids)]) + note = "" + hours = 0.0 + categories = self.env["fsm.category"] + for template in templates: + note += template.instructions or "" + hours += template.duration + categories |= template.category_ids + return { + "location_id": self.fsm_location_id.id, + "location_directions": self.fsm_location_id.direction, + "request_early": self.expected_date, + "scheduled_date_start": self.expected_date, + "todo": note, + "category_ids": [(6, 0, categories.ids)], + "scheduled_duration": hours, + "sale_id": kwargs.get("so_id", False), + "sale_line_id": kwargs.get("sol_id", False), + "template_id": template_id, + "company_id": self.company_id.id, + } + + def _field_service_generation(self): + """ + Create Field Service Orders based on the products' configuration. + :rtype: list(FSM Orders) + :return: list of newly created FSM Orders + """ + res = [] + for sale in self: + # Process lines set to FSM Sale + new_fsm_sale_lines = sale.order_line.filtered( + lambda l: l.product_id.field_service_tracking == "sale" + and not l.fsm_order_id + ) + if new_fsm_sale_lines: + fsm_by_sale = self.env["fsm.order"].search( + [("sale_id", "=", sale.id), ("sale_line_id", "=", False)] + ) + if not fsm_by_sale: + templates = new_fsm_sale_lines.product_id.fsm_order_template_id + vals = sale._prepare_fsm_values( + so_id=sale.id, template_ids=templates.ids + ) + fsm_by_sale = self.env["fsm.order"].sudo().create(vals) + res.append(fsm_by_sale) + new_fsm_sale_lines.write({"fsm_order_id": fsm_by_sale.id}) + # Create new FSM Order for lines set to FSM Line + new_fsm_line_lines = sale.order_line.filtered( + lambda l: l.product_id.field_service_tracking == "line" + and not l.fsm_order_id + ) + for line in new_fsm_line_lines: + vals = sale._prepare_fsm_values( + template_id=line.product_id.fsm_order_template_id.id, + so_id=self.id, + sol_id=line.id, + ) + fsm_by_line = self.env["fsm.order"].sudo().create(vals) + line.write({"fsm_order_id": fsm_by_line.id}) + res.append(fsm_by_line) + if len(res) > 0: + sale._post_fsm_message(res) + return res + + def _post_fsm_message(self, fsm_orders): + """ + Post messages to the Sale Order and the newly created FSM Orders + """ + self.ensure_one() + msg_fsm_links = "" + for fsm_order in fsm_orders: + fsm_order.message_post_with_view( + "mail.message_origin_link", + values={"self": fsm_order, "origin": self}, + subtype_id=self.env.ref("mail.mt_note").id, + author_id=self.env.user.partner_id.id, + ) + msg_fsm_links += ( + " {},".format( + fsm_order.id, fsm_order.name + ) + ) + so_msg_body = _("Field Service Order(s) Created: %s", msg_fsm_links) + self.message_post(body=so_msg_body[:-1]) + + def _action_confirm(self): + """On SO confirmation, some lines generate field service orders.""" + result = super(SaleOrder, self)._action_confirm() + if any( + sol.product_id.field_service_tracking != "no" + for sol in self.order_line.filtered( + lambda x: x.display_type not in ("line_section", "line_note") + ) + ): + if not self.fsm_location_id: + raise ValidationError(_("FSM Location must be set")) + self._field_service_generation() + return result + + def action_view_fsm_order(self): + fsm_orders = self.mapped("fsm_order_ids") + action = self.env["ir.actions.act_window"]._for_xml_id( + "fieldservice.action_fsm_dash_order" + ) + if len(fsm_orders) > 1: + action["domain"] = [("id", "in", fsm_orders.ids)] + elif len(fsm_orders) == 1: + action["views"] = [(self.env.ref("fieldservice.fsm_order_form").id, "form")] + action["res_id"] = fsm_orders.id + else: + action = {"type": "ir.actions.act_window_close"} + return action diff --git a/fieldservice_sale/models/sale_order_line.py b/fieldservice_sale/models/sale_order_line.py new file mode 100644 index 0000000000..421d33f939 --- /dev/null +++ b/fieldservice_sale/models/sale_order_line.py @@ -0,0 +1,60 @@ +# Copyright (C) 2019 Brian McMaster +# Copyright (C) 2019 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + qty_delivered_method = fields.Selection( + selection_add=[("field_service", "Field Service Order")], + ondelete={"field_service": "cascade"}, + ) + fsm_order_id = fields.Many2one( + "fsm.order", + "Order", + index=True, + copy=False, + help="Field Service Order generated by the sales order item", + ) + + @api.depends("product_id.type") + def _compute_product_updatable(self): + res = super()._compute_product_updatable() + for line in self: + if line.product_id.type == "service" and line.state == "sale": + line.product_updatable = False + return res + + @api.depends("product_id") + def _compute_qty_delivered_method(self): + res = super()._compute_qty_delivered_method() + for line in self: + if not line.is_expense and line.product_id.field_service_tracking == "line": + line.qty_delivered_method = "field_service" + return res + + @api.depends("fsm_order_id.stage_id") + def _compute_qty_delivered(self): + res = super()._compute_qty_delivered() + stage_complete = self.env.ref("fieldservice.fsm_stage_completed") + fsm_lines = self.filtered(lambda l: l.qty_delivered_method == "field_service") + for line in fsm_lines: + if line.fsm_order_id.stage_id == stage_complete: + line.qty_delivered = line.product_uom_qty + return res + + @api.model_create_multi + def create(self, vals_list): + lines = super(SaleOrderLine, self).create(vals_list) + for line in lines: + if line.state == "sale": + line.order_id._field_service_generation() + return line + + def _prepare_invoice_line(self, **optional_values): + res = super()._prepare_invoice_line(**optional_values) + if self.fsm_order_id: + res.update({"fsm_order_ids": [(4, self.fsm_order_id.id)]}) + return res diff --git a/fieldservice_sale/readme/CONFIGURE.rst b/fieldservice_sale/readme/CONFIGURE.rst new file mode 100644 index 0000000000..3d35ff83f2 --- /dev/null +++ b/fieldservice_sale/readme/CONFIGURE.rst @@ -0,0 +1,29 @@ +Products must be configured properly in order to create field service +orders upon sale order confirmation. + +The field service tracking of a product defines how it generates a field service +order if the product is sold via sale order. + +To configure a product that generates a unique field service order on each +sale order line: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Field Service Tracking to 'One FSM Order per Sale Order Line' +* Select the FSM Order Template that will be used for creating FSM Orders when + a Sale Order is confirmed with this product + +To configure a product that generates a unique field service order for +an individual sale order: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Field Service Tracking to 'One FSM Order per Sale Order' +* Select the FSM Order Template that will be used for creating FSM Orders when + a Sale Order is confirmed with this product + +To setup a sales territory: + +* Go to Field Service > Master Data > Locations +* Create or select a location +* Go to the Sales tab and select the sales territory diff --git a/fieldservice_sale/readme/CONTRIBUTORS.rst b/fieldservice_sale/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..61993c265b --- /dev/null +++ b/fieldservice_sale/readme/CONTRIBUTORS.rst @@ -0,0 +1,15 @@ +* Open Source Integrators + + * Steve Campbell + * Maxime Chambreuil + * Wolfgang Hall + * Raphael Lee + +* Serpent Consulting Services Pvt. Ltd. +* Brian McMaster +* Rapha??l Reverdy +* Cl??ment Mombereau + +* `Tecnativa `_: + + * Stefan Ungureanu diff --git a/fieldservice_sale/readme/DESCRIPTION.rst b/fieldservice_sale/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..4028d3f860 --- /dev/null +++ b/fieldservice_sale/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +The module integrates the Field Service application with the Sales one and +allows you to sell products that generate field service orders. diff --git a/fieldservice_sale/readme/INSTALL.rst b/fieldservice_sale/readme/INSTALL.rst new file mode 100644 index 0000000000..e5355c4b0f --- /dev/null +++ b/fieldservice_sale/readme/INSTALL.rst @@ -0,0 +1,4 @@ +To install Field Service and have the mapping features, you need to install GeoEngine. + +Please refer to the installation instructions available at: +https://github.com/OCA/geospatial/tree/13.0/base_geoengine diff --git a/fieldservice_sale/readme/ROADMAP.rst b/fieldservice_sale/readme/ROADMAP.rst new file mode 100644 index 0000000000..cff5b81aa8 --- /dev/null +++ b/fieldservice_sale/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* Provide a mapping between an address and the branch and use it to set the + pricelist of a new partner diff --git a/fieldservice_sale/readme/USAGE.rst b/fieldservice_sale/readme/USAGE.rst new file mode 100644 index 0000000000..c7cb6c41e5 --- /dev/null +++ b/fieldservice_sale/readme/USAGE.rst @@ -0,0 +1,9 @@ +* Go to Sales +* Create a new Quotation/Sale Order +* Set the FSM Location to be used +* On a Sale Order Line, select a product configured for field service orders +* Confirm the Sale Order +* Field Service orders linked to SO lines are created +* When a Field Service order is completed, the quantity delivered for its + linked sale order line will be updated to the quantity ordered, indicating + this line is ready for invoicing. diff --git a/fieldservice_sale/security/ir.model.access.csv b/fieldservice_sale/security/ir.model.access.csv new file mode 100644 index 0000000000..595094f653 --- /dev/null +++ b/fieldservice_sale/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_sale_order_fsm_user,sale.order.fsm.user,model_sale_order,fieldservice.group_fsm_user,1,0,0,0 diff --git a/fieldservice_sale/security/res_groups.xml b/fieldservice_sale/security/res_groups.xml new file mode 100644 index 0000000000..72d701425e --- /dev/null +++ b/fieldservice_sale/security/res_groups.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/fieldservice_sale/static/description/icon.png b/fieldservice_sale/static/description/icon.png new file mode 100644 index 0000000000..955674d8f0 Binary files /dev/null and b/fieldservice_sale/static/description/icon.png differ diff --git a/fieldservice_sale/static/description/index.html b/fieldservice_sale/static/description/index.html new file mode 100644 index 0000000000..2ad8aa966e --- /dev/null +++ b/fieldservice_sale/static/description/index.html @@ -0,0 +1,501 @@ + + + + + + +Field Service - Sales + + + +
+

Field Service - Sales

+ + +

Beta License: AGPL-3 OCA/field-service Translate me on Weblate Try me on Runboat

+

The module integrates the Field Service application with the Sales one and +allows you to sell products that generate field service orders.

+

Table of contents

+ +
+

Installation

+

To install Field Service and have the mapping features, you need to install GeoEngine.

+

Please refer to the installation instructions available at: +https://github.com/OCA/geospatial/tree/13.0/base_geoengine

+
+
+

Configuration

+

Products must be configured properly in order to create field service +orders upon sale order confirmation.

+

The field service tracking of a product defines how it generates a field service +order if the product is sold via sale order.

+

To configure a product that generates a unique field service order on each +sale order line:

+
    +
  • Go to Sales > Catalog > Products
  • +
  • Create or select a product
  • +
  • Set the Field Service Tracking to ‘One FSM Order per Sale Order Line’
  • +
  • Select the FSM Order Template that will be used for creating FSM Orders when +a Sale Order is confirmed with this product
  • +
+

To configure a product that generates a unique field service order for +an individual sale order:

+
    +
  • Go to Sales > Catalog > Products
  • +
  • Create or select a product
  • +
  • Set the Field Service Tracking to ‘One FSM Order per Sale Order’
  • +
  • Select the FSM Order Template that will be used for creating FSM Orders when +a Sale Order is confirmed with this product
  • +
+

To setup a sales territory:

+
    +
  • Go to Field Service > Master Data > Locations
  • +
  • Create or select a location
  • +
  • Go to the Sales tab and select the sales territory
  • +
+
+
+

Usage

+
    +
  • Go to Sales
  • +
  • Create a new Quotation/Sale Order
  • +
  • Set the FSM Location to be used
  • +
  • On a Sale Order Line, select a product configured for field service orders
  • +
  • Confirm the Sale Order
  • +
  • Field Service orders linked to SO lines are created
  • +
  • +
    When a Field Service order is completed, the quantity delivered for its
    +
    linked sale order line will be updated to the quantity ordered, indicating +this line is ready for invoicing.
    +
    +
  • +
+
+
+

Known issues / Roadmap

+
    +
  • Provide a mapping between an address and the branch and use it to set the +pricelist of a new partner
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Open Source Integrators
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainers:

+

wolfhall max3903 brian10048

+

This module is part of the OCA/field-service project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/fieldservice_sale/tests/__init__.py b/fieldservice_sale/tests/__init__.py new file mode 100644 index 0000000000..adc9a716b7 --- /dev/null +++ b/fieldservice_sale/tests/__init__.py @@ -0,0 +1,9 @@ +# Copyright (C) 2019 Clément Mombereau (Akretion) +# Copyright (C) 2019 Brian McMaster +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from . import ( + test_fsm_sale_autofill_location, + test_fsm_sale_common, + test_fsm_sale_order, +) diff --git a/fieldservice_sale/tests/test_fsm_sale_autofill_location.py b/fieldservice_sale/tests/test_fsm_sale_autofill_location.py new file mode 100644 index 0000000000..065ab63a82 --- /dev/null +++ b/fieldservice_sale/tests/test_fsm_sale_autofill_location.py @@ -0,0 +1,98 @@ +# Copyright (C) 2019 Clément Mombereau (Akretion) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from odoo.tests.common import Form, TransactionCase + + +class FSMSale(TransactionCase): + @classmethod + def setUpClass(cls): + """Create 3 related partners : a parent company, a child partner and + a child shipping partner. + + For each test, a different partner is a fsm_location. + A SO is created with the child partner as customer. The test run + the SO's location autofill and check if the fsm_location_id + is the expected one. + """ + super().setUpClass() + # create a parent company + cls.commercial_partner = cls.env["res.partner"].create( + {"name": "Company Commercial Partner", "is_company": True} + ) + # create a child partner + cls.partner = cls.env["res.partner"].create( + {"name": "Child Partner 1", "parent_id": cls.commercial_partner.id} + ) + # create a child partner shipping address + cls.shipping_partner = cls.env["res.partner"].create( + { + "name": "Shipping Partner", + "parent_id": cls.commercial_partner.id, + "type": "delivery", + } + ) + # Demo FS location + cls.location1 = cls.env.ref("fieldservice.location_1") + cls.location2 = cls.env.ref("fieldservice.location_2") + cls.location3 = cls.env.ref("fieldservice.location_3") + + def test_00_autofill_so_fsm_location(self): + """Check location autofill from SO partner + + SO partner is an FSM location linked to location 2 => expect location2 + (location 1 and 3 are ignored because we want only location explicitly + linked to the partner) + """ + self.partner.fsm_location = True + self.location1.partner_id = self.commercial_partner + self.location2.partner_id = self.partner + self.location3.partner_id = self.shipping_partner + with Form(self.env["sale.order"]) as so_form: + so_form.partner_id = self.partner + so = so_form.save() + self.assertEqual(so.fsm_location_id, self.location2) + + def test_01_autofill_so_fsm_location(self): + """Check location autofill from SO partner + + SO partner is not an FSM location defined, but location1 is linked to + its commercial partner => expect location 1 (because of ordering) + """ + self.partner.fsm_location = False + self.location1.partner_id = self.commercial_partner + self.location2.partner_id = self.partner + self.location3.partner_id = self.shipping_partner + with Form(self.env["sale.order"]) as so_form: + so_form.partner_id = self.partner + so = so_form.save() + self.assertEqual(so.fsm_location_id, self.location1) + + def test_02_autofill_so_fsm_location(self): + """Check location autofill from SO partner + + SO partner is not an FSM location defined, but location1 is linked to + the partner itself => expect location 1 (because of ordering) + """ + self.partner.fsm_location = False + self.location1.partner_id = self.partner + self.location2.partner_id = self.shipping_partner + self.location3.partner_id = self.commercial_partner + with Form(self.env["sale.order"]) as so_form: + so_form.partner_id = self.partner + so = so_form.save() + self.assertEqual(so.fsm_location_id, self.location1) + + def test_03_autofill_so_fsm_location(self): + """Check location autofill from SO partner + + SO partner is not an FSM location defined, but location1 is linked to + its shipping partner => expect location 1 (because of ordering) + """ + self.partner.fsm_location = False + self.location1.partner_id = self.shipping_partner + self.location2.partner_id = self.commercial_partner + self.location3.partner_id = self.partner + with Form(self.env["sale.order"]) as so_form: + so_form.partner_id = self.partner + so = so_form.save() + self.assertEqual(so.fsm_location_id, self.location1) diff --git a/fieldservice_sale/tests/test_fsm_sale_common.py b/fieldservice_sale/tests/test_fsm_sale_common.py new file mode 100644 index 0000000000..ab04b3989d --- /dev/null +++ b/fieldservice_sale/tests/test_fsm_sale_common.py @@ -0,0 +1,129 @@ +# Copyright (C) 2019 Brian McMaster +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.addons.sale.tests.common import TestSaleCommonBase + + +class TestFSMSale(TestSaleCommonBase): + @classmethod + def setUpClass(cls): + super(TestFSMSale, cls).setUpClass() + + @classmethod + def setUpFSMTemplates(cls): + # Create some templates to use on the FSM products + FSMTemplate = cls.env["fsm.template"] + + # Template 1 + cls.fsm_template_1 = FSMTemplate.create( + { + "name": "Test FSM Template #1", + "instructions": "These are the instructions for Template #1", + "duration": 2.25, + } + ) + # Template 2 + cls.fsm_template_2 = FSMTemplate.create( + { + "name": "Test FSM Template #2", + "instructions": "Template #2 requires a lot of work", + "duration": 4.5, + } + ) + # Template 3 + cls.fsm_template_3 = FSMTemplate.create( + { + "name": "Test FSM Template #3", + "instructions": "Complete the steps outlined for Template #3", + "duration": 0.75, + } + ) + # Template 4 + cls.fsm_template_4 = FSMTemplate.create( + { + "name": "Test FSM Template #4", + "instructions": "These notes apply to Template #4", + "duration": 0.75, + } + ) + + @classmethod + def setUpFSMProducts(cls): + cls.setUpFSMTemplates() + # Product 1 that creates one FSM Order per SO + cls.fsm_per_order_1 = cls.env["product.product"].create( + { + "name": "FSM Order per Sale Order #1", + "categ_id": cls.env.ref("product.product_category_3").id, + "standard_price": 85.0, + "list_price": 90.0, + "type": "service", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_unit").id, + "invoice_policy": "order", + "field_service_tracking": "sale", + "fsm_order_template_id": cls.fsm_template_1.id, + } + ) + + # Product 2 that creates one FSM Order per SO + cls.fsm_per_order_2 = cls.env["product.product"].create( + { + "name": "FSM Order per Sale Order #2", + "categ_id": cls.env.ref("product.product_category_3").id, + "standard_price": 125.0, + "list_price": 140.0, + "type": "service", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_unit").id, + "invoice_policy": "order", + "field_service_tracking": "sale", + "fsm_order_template_id": cls.fsm_template_2.id, + } + ) + # Product 1 that creates one FSM Order per SO Line + cls.fsm_per_line_1 = cls.env["product.product"].create( + { + "name": "FSM Order per SO Line #1", + "categ_id": cls.env.ref("product.product_category_3").id, + "standard_price": 75.0, + "list_price": 80.0, + "type": "service", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_unit").id, + "invoice_policy": "delivery", + "field_service_tracking": "line", + "fsm_order_template_id": cls.fsm_template_3.id, + } + ) + # Product 2 that creates one FSM Order per SO Line + cls.fsm_per_line_2 = cls.env["product.product"].create( + { + "name": "FSM Order per SO Line #2", + "categ_id": cls.env.ref("product.product_category_3").id, + "standard_price": 75.0, + "list_price": 80.0, + "type": "service", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_unit").id, + "invoice_policy": "delivery", + "field_service_tracking": "line", + "fsm_order_template_id": cls.fsm_template_4.id, + } + ) + # Normal Product + cls.product_line = cls.env["product.template"].create( + { + "name": "FSM Order per SO Line #2", + "categ_id": cls.env.ref("product.product_category_3").id, + "standard_price": 75.0, + "list_price": 80.0, + "type": "service", + "uom_id": cls.env.ref("uom.product_uom_unit").id, + "uom_po_id": cls.env.ref("uom.product_uom_unit").id, + "invoice_policy": "delivery", + "field_service_tracking": "no", + "fsm_order_template_id": cls.fsm_template_4.id, + } + ) + cls.product_line._onchange_field_service_tracking() diff --git a/fieldservice_sale/tests/test_fsm_sale_order.py b/fieldservice_sale/tests/test_fsm_sale_order.py new file mode 100644 index 0000000000..21925c800a --- /dev/null +++ b/fieldservice_sale/tests/test_fsm_sale_order.py @@ -0,0 +1,531 @@ +# Copyright (C) 2019 Brian McMaster +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields +from odoo.exceptions import ValidationError + +from .test_fsm_sale_common import TestFSMSale + + +class TestFSMSaleOrder(TestFSMSale): + @classmethod + def setUpClass(cls): + super(TestFSMSaleOrder, cls).setUpClass() + cls.test_location = cls.env.ref("fieldservice.test_location") + + # Setup products that when sold will create some FSM orders + cls.setUpFSMProducts() + cls.partner_customer_usd = cls.env["res.partner"].create( + { + "name": "partner_a", + "company_id": False, + } + ) + cls.pricelist_usd = cls.env["product.pricelist"].search( + [("currency_id.name", "=", "USD")], limit=1 + ) + # Create some sale orders that will use the above products + SaleOrder = cls.env["sale.order"].with_context(tracking_disable=True) + # create a generic Sale Order with one product + # set to create FSM service per sale order + cls.sale_order = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sale_order_wo_sol = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sale_order_sol = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sol_service_per_order = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_order_1.name, + "product_id": cls.fsm_per_order_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_order_1.uom_id.id, + "price_unit": cls.fsm_per_order_1.list_price, + "order_id": cls.sale_order.id, + "tax_id": False, + } + ) + # cls.sol_service_per_order._compute_product_updatable() + cls.sale_order_1 = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "fsm_location_id": cls.test_location.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sol_service_per_order_1 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_order_1.name, + "product_id": cls.fsm_per_order_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_order_1.uom_id.id, + "price_unit": cls.fsm_per_order_1.list_price, + "order_id": cls.sale_order_1.id, + "tax_id": False, + } + ) + # create a generic Sale Order with one product + # set to create FSM service per sale order line + cls.sale_order_2 = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "fsm_location_id": cls.test_location.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sol_service_per_line_1 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_line_1.name, + "product_id": cls.fsm_per_line_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_line_1.uom_id.id, + "price_unit": cls.fsm_per_line_1.list_price, + "order_id": cls.sale_order_2.id, + "tax_id": False, + } + ) + # create a generic Sale Order with multiple products + # set to create FSM service per sale order line + cls.sale_order_3 = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "fsm_location_id": cls.test_location.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sol_service_per_line_2 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_line_1.name, + "product_id": cls.fsm_per_line_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_line_1.uom_id.id, + "price_unit": cls.fsm_per_line_1.list_price, + "order_id": cls.sale_order_3.id, + "tax_id": False, + } + ) + cls.sol_service_per_line_3 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_line_2.name, + "product_id": cls.fsm_per_line_2.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_line_2.uom_id.id, + "price_unit": cls.fsm_per_line_2.list_price, + "order_id": cls.sale_order_3.id, + "tax_id": False, + } + ) + # create a generic Sale Order with mixed products + # 2 lines based on service per sale order line + # 2 lines based on service per sale order + cls.sale_order_4 = SaleOrder.create( + { + "partner_id": cls.partner_customer_usd.id, + "fsm_location_id": cls.test_location.id, + "pricelist_id": cls.pricelist_usd.id, + } + ) + cls.sol_service_per_line_4 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_line_1.name, + "product_id": cls.fsm_per_line_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_line_1.uom_id.id, + "price_unit": cls.fsm_per_line_1.list_price, + "order_id": cls.sale_order_4.id, + "tax_id": False, + } + ) + cls.sol_service_per_line_5 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_line_2.name, + "product_id": cls.fsm_per_line_2.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_line_2.uom_id.id, + "price_unit": cls.fsm_per_line_2.list_price, + "order_id": cls.sale_order_4.id, + "tax_id": False, + } + ) + cls.sol_service_per_order_2 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_order_1.name, + "product_id": cls.fsm_per_order_1.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_order_1.uom_id.id, + "price_unit": cls.fsm_per_order_1.list_price, + "order_id": cls.sale_order_4.id, + "tax_id": False, + } + ) + cls.sol_service_per_order_3 = cls.env["sale.order.line"].create( + { + "name": cls.fsm_per_order_2.name, + "product_id": cls.fsm_per_order_2.id, + "product_uom_qty": 1, + "product_uom": cls.fsm_per_order_2.uom_id.id, + "price_unit": cls.fsm_per_order_2.list_price, + "order_id": cls.sale_order_4.id, + "tax_id": False, + } + ) + + def _isp_account_installed(self): + """Checks if module is installed which will require more + logic for the tests. + :return Boolean indicating the installed status of the module + """ + result = False + isp_account_module = self.env["ir.module.module"].search( + [("name", "=", "fieldservice_isp_account")] + ) + if isp_account_module and isp_account_module.state == "installed": + result = True + return result + + def _fulfill_order(self, order): + """Extra logic required to fulfill FSM order status and prevent + validation error when attempting to complete the FSM order + :return FSM Order with additional fields set + """ + analytic_account = self.env.ref("analytic.analytic_administratif") + self.test_location.analytic_account_id = analytic_account.id + timesheet = self.env["account.analytic.line"].create( + { + "name": "timesheet_line", + "unit_amount": 1, + "account_id": analytic_account.id, + "user_id": self.env.ref("base.partner_admin").id, + "product_id": self.env.ref( + "fieldservice_isp_account.field_service_regular_time" + ).id, + } + ) + order.write( + { + "employee_timesheet_ids": [(6, 0, timesheet.ids)], + } + ) + return order + + def test_sale_order_0(self): + """Test the sales order 0 flow from sale to invoice. + - One FSM order linked to the Sale Order should be created. + - One Invoice linked to the FSM Order should be created. + """ + # Confirm the sale order + sol = self.sol_service_per_order + with self.assertRaises(ValidationError), self.cr.savepoint(): + self.sale_order.action_confirm() + + sol._compute_product_updatable() + # 1 FSM order created + + def test_sale_order_1(self): + """Test the sales order 1 flow from sale to invoice. + - One FSM order linked to the Sale Order should be created. + - One Invoice linked to the FSM Order should be created. + """ + # Confirm the sale order + self.sale_order_1.action_confirm() + # 1 FSM order created + self.assertEqual( + len(self.sale_order_1.fsm_order_ids.ids), + 1, + "FSM Sale: Sale Order 1 should create 1 FSM Order", + ) + FSM_Order = self.env["fsm.order"] + fsm_order = FSM_Order.search( + [("id", "=", self.sale_order_1.fsm_order_ids[0].id)] + ) + # Sale Order linked to FSM order + self.assertEqual( + len(fsm_order.ids), 1, "FSM Sale: Sale Order not linked to FSM Order" + ) + + # Complete the FSM order + if self._isp_account_installed(): + fsm_order = self._fulfill_order(fsm_order) + fsm_order.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order.action_complete() + + # Invoice the order + invoice = self.sale_order_1._create_invoices() + # 1 invoices created + self.assertEqual( + len(invoice.ids), 1, "FSM Sale: Sale Order 1 should create 1 invoice" + ) + self.assertTrue( + fsm_order in invoice.fsm_order_ids, + "FSM Sale: Invoice should be linked to FSM Order", + ) + + def test_sale_order_2(self): + """Test the sales order 2 flow from sale to invoice. + - One FSM order linked to the Sale Order Line should be created. + - The FSM Order should update qty_delivered when completed. + - One Invoice linked to the FSM Order should be created. + """ + sol = self.sol_service_per_line_1 + # Confirm the sale order + self.sale_order_2.action_confirm() + # 1 order created + self.assertEqual( + len(self.sale_order_2.fsm_order_ids.ids), + 1, + "FSM Sale: Sale Order 2 should create 1 FSM Order", + ) + FSM_Order = self.env["fsm.order"] + + fsm_order = FSM_Order.search([("id", "=", sol.fsm_order_id.id)]) + # SOL linked to FSM order + self.assertTrue( + sol.fsm_order_id.id == fsm_order.id, + "FSM Sale: Sale Order 2 Line not linked to FSM Order", + ) + + # Complete the FSM order + if self._isp_account_installed(): + fsm_order = self._fulfill_order(fsm_order) + fsm_order.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order.action_complete() + # qty delivered should be updated + self.assertTrue( + sol.qty_delivered == sol.product_uom_qty, + "FSM Sale: Sale Order Line qty delivered not equal to qty ordered", + ) + + # Invoice the order + invoice = self.sale_order_2._create_invoices() + # 1 invoice created + self.assertEqual( + len(invoice.ids), 1, "FSM Sale: Sale Order 2 should create 1 invoice" + ) + self.assertTrue( + fsm_order in invoice.fsm_order_ids, + "FSM Sale: Invoice should be linked to FSM Order", + ) + + def test_sale_order_3(self): + """Test sale order 3 flow from sale to invoice. + - An FSM order should be created for each Sale Order Line. + - The FSM Order should update qty_delivered when completed. + - An Invoice linked to each FSM Order should be created. + """ + sol1 = self.sol_service_per_line_2 + sol2 = self.sol_service_per_line_3 + + # Confirm the sale order + self.sale_order_3.action_confirm() + # 2 orders created and SOLs linked to FSM orders + self.assertEqual( + len(self.sale_order_3.fsm_order_ids.ids), + 2, + "FSM Sale: Sale Order 3 should create 2 FSM Orders", + ) + FSM_Order = self.env["fsm.order"] + fsm_order_1 = FSM_Order.search([("id", "=", sol1.fsm_order_id.id)]) + self.assertTrue( + sol1.fsm_order_id.id == fsm_order_1.id, + "FSM Sale: Sale Order Line 2 not linked to FSM Order", + ) + fsm_order_2 = FSM_Order.search([("id", "=", sol2.fsm_order_id.id)]) + self.assertTrue( + sol2.fsm_order_id.id == fsm_order_2.id, + "FSM Sale: Sale Order Line 3 not linked to FSM Order", + ) + + # Complete the FSM orders + if self._isp_account_installed(): + fsm_order_1 = self._fulfill_order(fsm_order_1) + fsm_order_1.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order_1.action_complete() + self.assertTrue( + sol1.qty_delivered == sol1.product_uom_qty, + "FSM Sale: Sale Order Line qty delivered not equal to qty ordered", + ) + if self._isp_account_installed(): + fsm_order_2 = self._fulfill_order(fsm_order_2) + fsm_order_2.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order_2.action_complete() + self.assertTrue( + sol2.qty_delivered == sol2.product_uom_qty, + "FSM Sale: Sale Order Line qty delivered not equal to qty ordered", + ) + + # Invoice the sale order + invoices = self.sale_order_3._create_invoices() + # 2 invoices created + self.assertEqual( + len(invoices.ids), 1, "FSM Sale: Sale Order 3 should create 1 invoices" + ) + inv_fsm_orders = FSM_Order + for inv in invoices: + inv_fsm_orders |= inv.fsm_order_ids + self.assertTrue( + fsm_order_1 in inv_fsm_orders, + "FSM Sale: FSM Order 1 should be linked to invoice", + ) + self.assertTrue( + fsm_order_2 in inv_fsm_orders, + "FSM Sale: FSM Order 2 should be linked to invoice", + ) + + def test_sale_order_4(self): + """Test sale order 4 flow from sale to invoice. + - Two FSM orders linked to the Sale Order Lines should be created. + - One FSM order linked to the Sale Order should be created. + - One Invoices should be created (One for each FSM Order). + """ + sol1 = self.sol_service_per_line_4 + sol2 = self.sol_service_per_line_5 + # sol3 = self.sol_service_per_order_2 + # sol4 = self.sol_service_per_order_3 + + # Confirm the sale order + self.sale_order_4.action_confirm() + # 3 orders created + self.assertEqual( + len(self.sale_order_4.fsm_order_ids.ids), + 3, + "FSM Sale: Sale Order 4 should create 3 FSM Orders", + ) + FSM_Order = self.env["fsm.order"] + fsm_order_1 = FSM_Order.search([("id", "=", sol1.fsm_order_id.id)]) + self.assertTrue( + sol1.fsm_order_id.id == fsm_order_1.id, + "FSM Sale: Sale Order Line not linked to FSM Order", + ) + fsm_order_2 = FSM_Order.search([("id", "=", sol2.fsm_order_id.id)]) + self.assertTrue( + sol2.fsm_order_id.id == fsm_order_2.id, + "FSM Sale: Sale Order Line not linked to FSM Order", + ) + fsm_order_3 = FSM_Order.search( + [ + ("id", "in", self.sale_order_4.fsm_order_ids.ids), + ("sale_line_id", "=", False), + ] + ) + self.assertEqual( + len(fsm_order_3.ids), 1, "FSM Sale: FSM Order not linked to Sale Order" + ) + + # Complete the FSM order + if self._isp_account_installed(): + fsm_order_1 = self._fulfill_order(fsm_order_1) + fsm_order_1.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order_1.action_complete() + self.assertTrue( + sol1.qty_delivered == sol1.product_uom_qty, + "FSM Sale: Sale Order Line qty delivered not equal to qty ordered", + ) + if self._isp_account_installed(): + fsm_order_2 = self._fulfill_order(fsm_order_2) + fsm_order_2.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order_2.action_complete() + self.assertTrue( + sol2.qty_delivered == sol2.product_uom_qty, + "FSM Sale: Sale Order Line qty delivered not equal to qty ordered", + ) + if self._isp_account_installed(): + fsm_order_3 = self._fulfill_order(fsm_order_3) + fsm_order_3.write( + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } + ) + fsm_order_3.action_complete() + # qty_delivered does not update for FSM orders linked only to the sale + + # Invoice the sale order + invoices = self.sale_order_4._create_invoices() + # 3 invoices created + self.assertEqual( + len(invoices.ids), 1, "FSM Sale: Sale Order 4 should create 1 invoice" + ) + + def test_sale_order_5(self): + """Test ValidationError isn't raised if order line + display_type in ("line_section", "line_note") + """ + # remove normal order line with display_type=False + self.sol_service_per_order.unlink() + # add note as order line to sale order + self.sol_note = self.env["sale.order.line"].create( + { + "name": "This is a note", + "display_type": "line_note", + "product_id": False, + "product_uom_qty": 0, + "product_uom": False, + "price_unit": 0, + "order_id": self.sale_order.id, + "tax_id": False, + } + ) + # confirm sale order: ValidationError shouldn't be raised + self.sale_order.action_confirm() + # set sale order to draft + self.sale_order.action_cancel() + self.sale_order.action_draft() + # remove note order line + self.sol_note.unlink() + # add section as order line to sale order + self.sol_section = self.env["sale.order.line"].create( + { + "name": "This is a section", + "display_type": "line_section", + "product_id": False, + "product_uom_qty": 0, + "product_uom": False, + "price_unit": 0, + "order_id": self.sale_order.id, + "tax_id": False, + } + ) + # confirm sale order: ValidationError shouldn't be raised + self.sale_order.action_confirm() diff --git a/fieldservice_sale/views/fsm_location.xml b/fieldservice_sale/views/fsm_location.xml new file mode 100644 index 0000000000..299767e5b9 --- /dev/null +++ b/fieldservice_sale/views/fsm_location.xml @@ -0,0 +1,20 @@ + + + + + fsm.location.form + fsm.location + + + + + + + + + + + + + + diff --git a/fieldservice_sale/views/fsm_order.xml b/fieldservice_sale/views/fsm_order.xml new file mode 100644 index 0000000000..0663e8e9e8 --- /dev/null +++ b/fieldservice_sale/views/fsm_order.xml @@ -0,0 +1,24 @@ + + + + fsm.order + + + + + + + + + diff --git a/fieldservice_sale/views/product_template.xml b/fieldservice_sale/views/product_template.xml new file mode 100644 index 0000000000..9296555491 --- /dev/null +++ b/fieldservice_sale/views/product_template.xml @@ -0,0 +1,18 @@ + + + product.template.fieldservice.form + product.template + + + + + + + + + + + diff --git a/fieldservice_sale/views/sale_order.xml b/fieldservice_sale/views/sale_order.xml new file mode 100644 index 0000000000..11c5c60f9f --- /dev/null +++ b/fieldservice_sale/views/sale_order.xml @@ -0,0 +1,28 @@ + + + sale.order.form.sale.fieldservice + sale.order + + + + + + + + + + + diff --git a/setup/fieldservice_sale/odoo/addons/fieldservice_sale b/setup/fieldservice_sale/odoo/addons/fieldservice_sale new file mode 120000 index 0000000000..a4b9cc32e8 --- /dev/null +++ b/setup/fieldservice_sale/odoo/addons/fieldservice_sale @@ -0,0 +1 @@ +../../../../fieldservice_sale \ No newline at end of file diff --git a/setup/fieldservice_sale/setup.py b/setup/fieldservice_sale/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/fieldservice_sale/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)