From fe8b543bfc136c8fc63644acef2e8708de01b48d Mon Sep 17 00:00:00 2001 From: osi-scampbell Date: Wed, 19 Dec 2018 15:50:26 -0700 Subject: [PATCH 01/77] [ADD] fieldservice_sale --- fieldservice_sale/README.rst | 121 +++++ fieldservice_sale/__init__.py | 4 + fieldservice_sale/__manifest__.py | 25 + fieldservice_sale/models/__init__.py | 4 + fieldservice_sale/models/fsm_sale.py | 13 + fieldservice_sale/readme/CONFIGURE.rst | 5 + fieldservice_sale/readme/CONTRIBUTORS.rst | 3 + fieldservice_sale/readme/CREDITS.rst | 3 + fieldservice_sale/readme/DESCRIPTION.rst | 1 + fieldservice_sale/readme/INSTALL.rst | 4 + fieldservice_sale/readme/ROADMAP.rst | 2 + fieldservice_sale/readme/USAGE.rst | 1 + .../static/description/description/icon.png | Bin 0 -> 17808 bytes .../static/description/description/index.html | 464 ++++++++++++++++++ .../static/description/index.html | 459 +++++++++++++++++ fieldservice_sale/views/fsm_location.xml | 19 + 16 files changed, 1128 insertions(+) create mode 100644 fieldservice_sale/README.rst create mode 100644 fieldservice_sale/__init__.py create mode 100644 fieldservice_sale/__manifest__.py create mode 100644 fieldservice_sale/models/__init__.py create mode 100644 fieldservice_sale/models/fsm_sale.py create mode 100644 fieldservice_sale/readme/CONFIGURE.rst create mode 100644 fieldservice_sale/readme/CONTRIBUTORS.rst create mode 100644 fieldservice_sale/readme/CREDITS.rst create mode 100644 fieldservice_sale/readme/DESCRIPTION.rst create mode 100644 fieldservice_sale/readme/INSTALL.rst create mode 100644 fieldservice_sale/readme/ROADMAP.rst create mode 100644 fieldservice_sale/readme/USAGE.rst create mode 100644 fieldservice_sale/static/description/description/icon.png create mode 100644 fieldservice_sale/static/description/description/index.html create mode 100644 fieldservice_sale/static/description/index.html create mode 100644 fieldservice_sale/views/fsm_location.xml diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst new file mode 100644 index 0000000000..e86745c429 --- /dev/null +++ b/fieldservice_sale/README.rst @@ -0,0 +1,121 @@ +===================== +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/11.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-11-0/field-service-11-0-fieldservice_sale + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/264/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +The module integrate the field service application with the sales one. + +**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/11.0/base_geoengine + +Configuration +============= + +To use this module, you need to: + +* Go to Field Service > Master Data > Locations +* Create or select a location +* Go to the Sales tab and select the sales territory + +Usage +===== + +Coming soon... + +Known issues / Roadmap +====================== + +The roadmap of the Field Service application is documented on +`Github `_. + +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 +~~~~~~~~~~~~ + +* Steve Campbell +* Maxime Chambreuil +* Wolfgang Hall + +Other credits +~~~~~~~~~~~~~ + +The development of this module has been financially supported by: + +* Open Source Integrators + +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 + +Current `maintainers `__: + +|maintainer-wolfhall| |maintainer-max3903| + +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..631bd4893a --- /dev/null +++ b/fieldservice_sale/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2018 - TODAY, 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..8e8741f7c8 --- /dev/null +++ b/fieldservice_sale/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright (C) 2018 - TODAY, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Field Service - Sales', + 'summary': 'Sales', + 'version': '11.0.0.0.1', + 'category': 'Field Service', + 'author': 'Open Source Integrators, Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/field-service', + 'depends': [ + 'fieldservice', + 'sale', + ], + 'data': [ + 'views/fsm_location.xml' + ], + 'application': True, + 'license': 'AGPL-3', + 'development_status': 'Beta', + 'maintainers': [ + 'wolfhall', + 'max3903', + ], +} diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py new file mode 100644 index 0000000000..61d98a615d --- /dev/null +++ b/fieldservice_sale/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2018 - TODAY, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import fsm_location diff --git a/fieldservice_sale/models/fsm_sale.py b/fieldservice_sale/models/fsm_sale.py new file mode 100644 index 0000000000..65416a8a7a --- /dev/null +++ b/fieldservice_sale/models/fsm_sale.py @@ -0,0 +1,13 @@ +# Copyright (C) 2018 - TODAY, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields + +from odoo.addons.base_geoengine import geo_model + + +class FSMLocation(geo_model.GeoModel): + _inherit = 'fsm.location' + + sales_territory_id = fields.Many2one('fsm.territory', + string='Sales Territory') diff --git a/fieldservice_sale/readme/CONFIGURE.rst b/fieldservice_sale/readme/CONFIGURE.rst new file mode 100644 index 0000000000..f2731c6102 --- /dev/null +++ b/fieldservice_sale/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +To use this module, you need to: + +* 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..1b9bde1401 --- /dev/null +++ b/fieldservice_sale/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Steve Campbell +* Maxime Chambreuil +* Wolfgang Hall diff --git a/fieldservice_sale/readme/CREDITS.rst b/fieldservice_sale/readme/CREDITS.rst new file mode 100644 index 0000000000..0eff0acf4e --- /dev/null +++ b/fieldservice_sale/readme/CREDITS.rst @@ -0,0 +1,3 @@ +The development of this module has been financially supported by: + +* Open Source Integrators diff --git a/fieldservice_sale/readme/DESCRIPTION.rst b/fieldservice_sale/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..b81fa62ffb --- /dev/null +++ b/fieldservice_sale/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +The module integrate the field service application with the sales one. diff --git a/fieldservice_sale/readme/INSTALL.rst b/fieldservice_sale/readme/INSTALL.rst new file mode 100644 index 0000000000..c010f8f6a2 --- /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/11.0/base_geoengine diff --git a/fieldservice_sale/readme/ROADMAP.rst b/fieldservice_sale/readme/ROADMAP.rst new file mode 100644 index 0000000000..f607015959 --- /dev/null +++ b/fieldservice_sale/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +The roadmap of the Field Service application is documented on +`Github `_. diff --git a/fieldservice_sale/readme/USAGE.rst b/fieldservice_sale/readme/USAGE.rst new file mode 100644 index 0000000000..684e27f7d7 --- /dev/null +++ b/fieldservice_sale/readme/USAGE.rst @@ -0,0 +1 @@ +Coming soon... diff --git a/fieldservice_sale/static/description/description/icon.png b/fieldservice_sale/static/description/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..955674d8f0b8c47de3ffa9db25cb109fbe4a1091 GIT binary patch literal 17808 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 literal 0 HcmV?d00001 diff --git a/fieldservice_sale/static/description/description/index.html b/fieldservice_sale/static/description/description/index.html new file mode 100644 index 0000000000..734a351843 --- /dev/null +++ b/fieldservice_sale/static/description/description/index.html @@ -0,0 +1,464 @@ + + + + + + +Field Service + + + +
+

Field Service

+ + +

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

+

This module is the base of the Field Service application in Odoo.

+

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/11.0/base_geoengine

+
+
+

Configuration

+

To configure this module, you need to:

+
    +
  • Go to Field Service > Configuration > Settings
  • +
+
+
+

Usage

+

To use this module, you need to:

+
    +
  • Go to Field Service
  • +
  • Create or select an order
  • +
  • Follow the process
  • +
+
+
+

Known issues / Roadmap

+

The roadmap of the Field Service application is documented on +Github.

+
+
+

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
  • +
+
+ +
+

Other credits

+

The development of this module has been financially supported by:

+ +
+
+

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

+

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/static/description/index.html b/fieldservice_sale/static/description/index.html new file mode 100644 index 0000000000..6d777250e3 --- /dev/null +++ b/fieldservice_sale/static/description/index.html @@ -0,0 +1,459 @@ + + + + + + +Field Service - Sales + + + +
+

Field Service - Sales

+ + +

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

+

The module integrate the field service application with the sales one.

+

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/11.0/base_geoengine

+
+
+

Configuration

+

To use this module, you need to:

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

Usage

+

Coming soon???

+
+
+

Known issues / Roadmap

+

The roadmap of the Field Service application is documented on +Github.

+
+
+

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
  • +
+
+ +
+

Other credits

+

The development of this module has been financially supported by:

+ +
+
+

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

+

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/views/fsm_location.xml b/fieldservice_sale/views/fsm_location.xml new file mode 100644 index 0000000000..886f431298 --- /dev/null +++ b/fieldservice_sale/views/fsm_location.xml @@ -0,0 +1,19 @@ + + + + + + fsm.location.form + fsm.location + + + + + + + + + + + + From a01e0721d7a5f4b734d139e8e5d6108fee5c76ee Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Thu, 20 Dec 2018 11:27:24 -0600 Subject: [PATCH 02/77] [REN] fsm_location.py --- fieldservice_sale/models/{fsm_sale.py => fsm_location.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename fieldservice_sale/models/{fsm_sale.py => fsm_location.py} (100%) diff --git a/fieldservice_sale/models/fsm_sale.py b/fieldservice_sale/models/fsm_location.py similarity index 100% rename from fieldservice_sale/models/fsm_sale.py rename to fieldservice_sale/models/fsm_location.py From c889775a5d8d59e9787988e7097faf46fa728c19 Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Thu, 20 Dec 2018 17:40:55 -0600 Subject: [PATCH 03/77] [FIX] View + icon --- fieldservice_sale/__manifest__.py | 1 - fieldservice_sale/static/description/icon.png | Bin 0 -> 17808 bytes fieldservice_sale/views/fsm_location.xml | 8 +++++--- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 fieldservice_sale/static/description/icon.png diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 8e8741f7c8..ada52ef64b 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -15,7 +15,6 @@ 'data': [ 'views/fsm_location.xml' ], - 'application': True, 'license': 'AGPL-3', 'development_status': 'Beta', 'maintainers': [ diff --git a/fieldservice_sale/static/description/icon.png b/fieldservice_sale/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..955674d8f0b8c47de3ffa9db25cb109fbe4a1091 GIT binary patch literal 17808 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 literal 0 HcmV?d00001 diff --git a/fieldservice_sale/views/fsm_location.xml b/fieldservice_sale/views/fsm_location.xml index 886f431298..b9be2f2f87 100644 --- a/fieldservice_sale/views/fsm_location.xml +++ b/fieldservice_sale/views/fsm_location.xml @@ -7,12 +7,14 @@ fsm.location - + - + + + - + From c2dd43d7b28cdacdd0049089451f748a54c392d0 Mon Sep 17 00:00:00 2001 From: Murtuza Saleh Date: Wed, 3 Apr 2019 20:53:20 +0530 Subject: [PATCH 04/77] [MIG][WIP][12.0] fieldservice_sale --- fieldservice_sale/README.rst | 13 +- fieldservice_sale/__manifest__.py | 3 +- fieldservice_sale/models/fsm_location.py | 6 +- fieldservice_sale/readme/CONTRIBUTORS.rst | 1 + fieldservice_sale/readme/INSTALL.rst | 2 +- .../static/description/description/icon.png | Bin 17808 -> 0 bytes .../static/description/description/index.html | 464 ------------------ .../static/description/index.html | 9 +- 8 files changed, 18 insertions(+), 480 deletions(-) delete mode 100644 fieldservice_sale/static/description/description/icon.png delete mode 100644 fieldservice_sale/static/description/description/index.html diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst index e86745c429..755ff8d4eb 100644 --- a/fieldservice_sale/README.rst +++ b/fieldservice_sale/README.rst @@ -14,13 +14,13 @@ Field Service - Sales :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/11.0/fieldservice_sale + :target: https://github.com/OCA/field-service/tree/12.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-11-0/field-service-11-0-fieldservice_sale + :target: https://translation.odoo-community.org/projects/field-service-12-0/field-service-12-0-fieldservice_sale :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/264/11.0 + :target: https://runbot.odoo-community.org/runbot/264/12.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -38,7 +38,7 @@ 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/11.0/base_geoengine +https://github.com/OCA/geospatial/tree/12.0/base_geoengine Configuration ============= @@ -66,7 +66,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -84,6 +84,7 @@ Contributors * Steve Campbell * Maxime Chambreuil * Wolfgang Hall +* Serpent Consulting Services Pvt. Ltd. Other credits ~~~~~~~~~~~~~ @@ -116,6 +117,6 @@ Current `maintainers `__: |maintainer-wolfhall| |maintainer-max3903| -This module is part of the `OCA/field-service `_ project on GitHub. +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/__manifest__.py b/fieldservice_sale/__manifest__.py index ada52ef64b..c06567201e 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'Field Service - Sales', 'summary': 'Sales', - 'version': '11.0.0.0.1', + 'version': '12.0.1.0.0', 'category': 'Field Service', 'author': 'Open Source Integrators, Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/field-service', @@ -21,4 +21,5 @@ 'wolfhall', 'max3903', ], + 'installable': True, } diff --git a/fieldservice_sale/models/fsm_location.py b/fieldservice_sale/models/fsm_location.py index 65416a8a7a..601c2408b2 100644 --- a/fieldservice_sale/models/fsm_location.py +++ b/fieldservice_sale/models/fsm_location.py @@ -1,12 +1,10 @@ # Copyright (C) 2018 - TODAY, Open Source Integrators # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields +from odoo import fields, models -from odoo.addons.base_geoengine import geo_model - -class FSMLocation(geo_model.GeoModel): +class FSMLocation(models.Model): _inherit = 'fsm.location' sales_territory_id = fields.Many2one('fsm.territory', diff --git a/fieldservice_sale/readme/CONTRIBUTORS.rst b/fieldservice_sale/readme/CONTRIBUTORS.rst index 1b9bde1401..c6a834aaa4 100644 --- a/fieldservice_sale/readme/CONTRIBUTORS.rst +++ b/fieldservice_sale/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * Steve Campbell * Maxime Chambreuil * Wolfgang Hall +* Serpent Consulting Services Pvt. Ltd. diff --git a/fieldservice_sale/readme/INSTALL.rst b/fieldservice_sale/readme/INSTALL.rst index c010f8f6a2..8571f65376 100644 --- a/fieldservice_sale/readme/INSTALL.rst +++ b/fieldservice_sale/readme/INSTALL.rst @@ -1,4 +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/11.0/base_geoengine +https://github.com/OCA/geospatial/tree/12.0/base_geoengine diff --git a/fieldservice_sale/static/description/description/icon.png b/fieldservice_sale/static/description/description/icon.png deleted file mode 100644 index 955674d8f0b8c47de3ffa9db25cb109fbe4a1091..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17808 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 diff --git a/fieldservice_sale/static/description/description/index.html b/fieldservice_sale/static/description/description/index.html deleted file mode 100644 index 734a351843..0000000000 --- a/fieldservice_sale/static/description/description/index.html +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - -Field Service - - - -
-

Field Service

- - -

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

-

This module is the base of the Field Service application in Odoo.

-

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/11.0/base_geoengine

-
-
-

Configuration

-

To configure this module, you need to:

-
    -
  • Go to Field Service > Configuration > Settings
  • -
-
-
-

Usage

-

To use this module, you need to:

-
    -
  • Go to Field Service
  • -
  • Create or select an order
  • -
  • Follow the process
  • -
-
-
-

Known issues / Roadmap

-

The roadmap of the Field Service application is documented on -Github.

-
-
-

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
  • -
-
- -
-

Other credits

-

The development of this module has been financially supported by:

- -
-
-

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

-

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/static/description/index.html b/fieldservice_sale/static/description/index.html index 6d777250e3..23490becee 100644 --- a/fieldservice_sale/static/description/index.html +++ b/fieldservice_sale/static/description/index.html @@ -367,7 +367,7 @@

Field Service - Sales

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

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

+

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

The module integrate the field service application with the sales one.

Table of contents

@@ -390,7 +390,7 @@

Field Service - Sales

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/11.0/base_geoengine

+https://github.com/OCA/geospatial/tree/12.0/base_geoengine

Configuration

@@ -415,7 +415,7 @@

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.

+feedback.

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

@@ -432,6 +432,7 @@

Contributors

  • Steve Campbell <scampbell@opensourceintegrators.com>
  • Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
  • Wolfgang Hall <whall@opensourceintegrators.com>
  • +
  • Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
  • @@ -450,7 +451,7 @@

    Maintainers

    promote its widespread use.

    Current maintainers:

    wolfhall max3903

    -

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

    +

    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.

    From bc402d47618dfdb9f09fe1f367f2c8c36a47a6dc Mon Sep 17 00:00:00 2001 From: scampbell Date: Wed, 26 Jun 2019 09:43:27 -0700 Subject: [PATCH 05/77] [IMP] FSM Sale Update [IMP] Remove Duplicate Field --- fieldservice_sale/views/fsm_location.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/fieldservice_sale/views/fsm_location.xml b/fieldservice_sale/views/fsm_location.xml index b9be2f2f87..88ae128d9c 100644 --- a/fieldservice_sale/views/fsm_location.xml +++ b/fieldservice_sale/views/fsm_location.xml @@ -12,6 +12,7 @@ + From df215d9717a9f4372a644613a8cc55b85f90e343 Mon Sep 17 00:00:00 2001 From: osi-scampbell Date: Wed, 19 Dec 2018 15:50:26 -0700 Subject: [PATCH 06/77] [ADD] fieldservice_sale --- fieldservice_sale/README.rst | 4 + fieldservice_sale/__manifest__.py | 1 + fieldservice_sale/models/fsm_sale.py | 13 + .../static/description/description/icon.png | Bin 0 -> 17808 bytes .../static/description/description/index.html | 464 ++++++++++++++++++ 5 files changed, 482 insertions(+) create mode 100644 fieldservice_sale/models/fsm_sale.py create mode 100644 fieldservice_sale/static/description/description/icon.png create mode 100644 fieldservice_sale/static/description/description/index.html diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst index 755ff8d4eb..39d9b32177 100644 --- a/fieldservice_sale/README.rst +++ b/fieldservice_sale/README.rst @@ -38,7 +38,11 @@ Installation To install Field Service and have the mapping features, you need to install GeoEngine. Please refer to the installation instructions available at: +<<<<<<< HEAD https://github.com/OCA/geospatial/tree/12.0/base_geoengine +======= +https://github.com/OCA/geospatial/tree/11.0/base_geoengine +>>>>>>> [UPD] README.rst Configuration ============= diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index c06567201e..9e9b1127a8 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -15,6 +15,7 @@ 'data': [ 'views/fsm_location.xml' ], + 'application': True, 'license': 'AGPL-3', 'development_status': 'Beta', 'maintainers': [ diff --git a/fieldservice_sale/models/fsm_sale.py b/fieldservice_sale/models/fsm_sale.py new file mode 100644 index 0000000000..65416a8a7a --- /dev/null +++ b/fieldservice_sale/models/fsm_sale.py @@ -0,0 +1,13 @@ +# Copyright (C) 2018 - TODAY, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields + +from odoo.addons.base_geoengine import geo_model + + +class FSMLocation(geo_model.GeoModel): + _inherit = 'fsm.location' + + sales_territory_id = fields.Many2one('fsm.territory', + string='Sales Territory') diff --git a/fieldservice_sale/static/description/description/icon.png b/fieldservice_sale/static/description/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..955674d8f0b8c47de3ffa9db25cb109fbe4a1091 GIT binary patch literal 17808 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 literal 0 HcmV?d00001 diff --git a/fieldservice_sale/static/description/description/index.html b/fieldservice_sale/static/description/description/index.html new file mode 100644 index 0000000000..734a351843 --- /dev/null +++ b/fieldservice_sale/static/description/description/index.html @@ -0,0 +1,464 @@ + + + + + + +Field Service + + + +
    +

    Field Service

    + + +

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

    +

    This module is the base of the Field Service application in Odoo.

    +

    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/11.0/base_geoengine

    +
    +
    +

    Configuration

    +

    To configure this module, you need to:

    +
      +
    • Go to Field Service > Configuration > Settings
    • +
    +
    +
    +

    Usage

    +

    To use this module, you need to:

    +
      +
    • Go to Field Service
    • +
    • Create or select an order
    • +
    • Follow the process
    • +
    +
    +
    +

    Known issues / Roadmap

    +

    The roadmap of the Field Service application is documented on +Github.

    +
    +
    +

    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
    • +
    +
    + +
    +

    Other credits

    +

    The development of this module has been financially supported by:

    + +
    +
    +

    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

    +

    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.

    +
    +
    +
    + + From eb955396025ec5a84be4d6e73609039b8e049fce Mon Sep 17 00:00:00 2001 From: Maxime Chambreuil Date: Thu, 20 Dec 2018 17:40:55 -0600 Subject: [PATCH 07/77] [FIX] View + icon --- fieldservice_sale/__manifest__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 9e9b1127a8..c06567201e 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -15,7 +15,6 @@ 'data': [ 'views/fsm_location.xml' ], - 'application': True, 'license': 'AGPL-3', 'development_status': 'Beta', 'maintainers': [ From 98bc149b811e2fcf4ea9e88190bbf5beaf391b50 Mon Sep 17 00:00:00 2001 From: brian10048 Date: Sat, 11 May 2019 17:54:52 -0400 Subject: [PATCH 08/77] [IMP] fieldservice_sale Added ability to link a product with FSM order template and create FSM orders upon sale order confirmation Added option to install fieldservice_sale module --- fieldservice_sale/__manifest__.py | 12 +- fieldservice_sale/models/__init__.py | 3 + fieldservice_sale/models/fsm_order.py | 23 ++++ fieldservice_sale/models/product.py | 26 ++++ fieldservice_sale/models/sale_order.py | 157 ++++++++++++++++++++++ fieldservice_sale/readme/CONFIGURE.rst | 12 +- fieldservice_sale/readme/CONTRIBUTORS.rst | 1 + fieldservice_sale/readme/USAGE.rst | 7 +- fieldservice_sale/views/fsm_order.xml | 19 +++ fieldservice_sale/views/product.xml | 16 +++ fieldservice_sale/views/sale_order.xml | 23 ++++ 11 files changed, 293 insertions(+), 6 deletions(-) create mode 100644 fieldservice_sale/models/fsm_order.py create mode 100644 fieldservice_sale/models/product.py create mode 100644 fieldservice_sale/models/sale_order.py create mode 100644 fieldservice_sale/views/fsm_order.xml create mode 100644 fieldservice_sale/views/product.xml create mode 100644 fieldservice_sale/views/sale_order.xml diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index c06567201e..8dee4eb29d 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -3,23 +3,27 @@ { 'name': 'Field Service - Sales', - 'summary': 'Sales', - 'version': '12.0.1.0.0', + 'version': '12.0.1.0.1', + 'summary': 'Sales integration for Field Service', 'category': 'Field Service', 'author': 'Open Source Integrators, Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/field-service', 'depends': [ 'fieldservice', - 'sale', + 'sale_management', ], 'data': [ - 'views/fsm_location.xml' + 'views/fsm_location.xml', + 'views/fsm_order.xml', + 'views/product.xml', + 'views/sale_order.xml', ], 'license': 'AGPL-3', 'development_status': 'Beta', 'maintainers': [ 'wolfhall', 'max3903', + 'brian10048', ], 'installable': True, } diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py index 61d98a615d..360a690640 100644 --- a/fieldservice_sale/models/__init__.py +++ b/fieldservice_sale/models/__init__.py @@ -2,3 +2,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import fsm_location +from . import product +from . import sale_order +from . import fsm_order diff --git a/fieldservice_sale/models/fsm_order.py b/fieldservice_sale/models/fsm_order.py new file mode 100644 index 0000000000..4798b725a1 --- /dev/null +++ b/fieldservice_sale/models/fsm_order.py @@ -0,0 +1,23 @@ +# Copyright (C) 2019 - TODAY, Brian McMaster, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, _ + +from odoo.addons.base_geoengine import geo_model + + +class FSMOrder(geo_model.GeoModel): + _inherit = 'fsm.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, + "context": {"create": False}, + "name": _("Sales Orders"), + } diff --git a/fieldservice_sale/models/product.py b/fieldservice_sale/models/product.py new file mode 100644 index 0000000000..9655b7dc2b --- /dev/null +++ b/fieldservice_sale/models/product.py @@ -0,0 +1,26 @@ +# Copyright (C) 2019 - TODAY, Brian McMaster, 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'), + ]) + field_service_tracking = fields.Selection([ + ('no', 'Don\'t create order'), + ('order', 'Create a single order'), + ], string="Field Service Tracking", default="no", + help="""On Sales order confirmation, this product can generate a field + service order.""") + 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 != 'order': + 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..46395a3967 --- /dev/null +++ b/fieldservice_sale/models/sale_order.py @@ -0,0 +1,157 @@ +# Copyright (C) 2019 - TODAY, Brian McMaster, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ + + +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") + fsm_order_ids = fields.Many2many( + 'fsm.order', compute='_compute_fsm_order_ids', + string='Field Service orders associated to this sale') + fsm_order_count = fields.Float( + string='Field Service Orders', compute='_compute_fsm_order_ids') + + @api.multi + @api.depends('order_line.product_id') + def _compute_fsm_order_ids(self): + for order in self: + order.fsm_order_ids = self.env['fsm.order'].search([ + ('sale_line_id', 'in', order.order_line.ids)]) + order.fsm_order_count = len(order.fsm_order_ids) + + @api.multi + def action_confirm(self): + """ On SO confirmation, some lines generate field service orders. """ + result = super(SaleOrder, self).action_confirm() + self.order_line._field_service_generation() + return result + + @api.multi + def action_view_fsm_order(self): + fsm_orders = self.mapped('fsm_order_ids') + action = self.env.ref('fieldservice.action_fsm_dash_order').read()[0] + 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 + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + fsm_order_id = fields.Many2one( + 'fsm.order', 'Order', index=True, + help="Field Service Order generated by the sales order item") + is_field_service = fields.Boolean( + "Is a Field Service", compute='_compute_is_field_service', + store=True, + help="""Sales Order item should generate an Order and/or + Order Recurrence, depending on the product settings.""") + + @api.multi + @api.depends('product_id.type') + def _compute_is_field_service(self): + for so_line in self: + so_line.is_field_service = so_line.product_id.type == 'service' + + @api.depends('product_id.type') + def _compute_product_updatable(self): + for line in self: + if line.product_id.type == 'service' and line.state == 'sale': + line.product_updatable = False + else: + super(SaleOrderLine, line)._compute_product_updatable() + + @api.model + def create(self, values): + line = super(SaleOrderLine, self).create(values) + if line.state == 'sale': + line._field_service_generation() + return line + + def _field_create_fsm_order_prepare_values(self): + self.ensure_one() + return { + 'customer_id': self.order_id.partner_id.id, + 'location_id': self.order_id.fsm_location_id.id, + # 'request_early': , + # 'scheduled_date_start': , + 'description': self.name, + 'template_id': self.product_id.fsm_order_template_id.id, + 'sale_line_id': self.id, + 'company_id': self.company_id.id, + } + + @api.multi + def _field_create_fsm_order(self): + """ Generate fsm_order for the given so line, and link it. + :return a mapping with the so line id and its linked fsm_order + :rtype dict + """ + result = {} + for so_line in self: + # create fsm_order + values = so_line._field_create_fsm_order_prepare_values() + fsm_order = self.env['fsm.order'].sudo().create(values) + so_line.write({'fsm_order_id': fsm_order.id}) + # post message on SO + msg_body = _( + """Field Service Order Created (%s): %s + """) % (so_line.product_id.name, fsm_order.id, fsm_order.name) + so_line.order_id.message_post(body=msg_body) + # post message on fsm_order + fsm_order_msg = _( + """This order has been created from: %s (%s) + """) % (so_line.order_id.id, so_line.order_id.name, + so_line.product_id.name) + fsm_order.message_post(body=fsm_order_msg) + + result[so_line.id] = fsm_order + return result + + @api.multi + def _field_find_fsm_order(self): + """ Find the fsm_order generated by the so lines. If no fsm_order + linked, it will be created automatically. + :return a mapping with the so line id and its linked fsm_order + :rtype dict + """ + # one search for all so lines + fsm_orders = self.env['fsm.order'].search([ + ('sale_line_id', 'in', self.ids)]) + fsm_order_sol_mapping = { + fsm_order.sale_line_id.id: fsm_order for fsm_order in fsm_orders} + + result = {} + for so_line in self: + # If the SO was confirmed, cancelled, set to draft then confirmed, + # avoid creating a new fsm_order. + fsm_order = fsm_order_sol_mapping.get(so_line.id) + # If not found, create one fsm_order for the so line + if not fsm_order: + fsm_order = so_line._field_create_fsm_order()[so_line.id] + result[so_line.id] = fsm_order + return result + + @api.multi + def _field_service_generation(self): + """ For service lines, create the field service order. If it already + exists, it simply links the existing one to the line. + """ + for so_line in self.filtered(lambda sol: sol.is_field_service): + # create order + if so_line.product_id.field_service_tracking == 'order': + so_line._field_find_fsm_order() diff --git a/fieldservice_sale/readme/CONFIGURE.rst b/fieldservice_sale/readme/CONFIGURE.rst index f2731c6102..f9e33986f8 100644 --- a/fieldservice_sale/readme/CONFIGURE.rst +++ b/fieldservice_sale/readme/CONFIGURE.rst @@ -1,4 +1,14 @@ -To use this module, you need to: +To setup a product for quoting and selling field service orders: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Product Type to 'Service' under General Information tab +* Under Invoicing tab, set the Field Service Tracking option +* 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, you need to: * Go to Field Service > Master Data > Locations * Create or select a location diff --git a/fieldservice_sale/readme/CONTRIBUTORS.rst b/fieldservice_sale/readme/CONTRIBUTORS.rst index c6a834aaa4..997a52c353 100644 --- a/fieldservice_sale/readme/CONTRIBUTORS.rst +++ b/fieldservice_sale/readme/CONTRIBUTORS.rst @@ -2,3 +2,4 @@ * Maxime Chambreuil * Wolfgang Hall * Serpent Consulting Services Pvt. Ltd. +* Brian McMaster diff --git a/fieldservice_sale/readme/USAGE.rst b/fieldservice_sale/readme/USAGE.rst index 684e27f7d7..21658803b6 100644 --- a/fieldservice_sale/readme/USAGE.rst +++ b/fieldservice_sale/readme/USAGE.rst @@ -1 +1,6 @@ -Coming soon... +* Go to Sales app +* 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 diff --git a/fieldservice_sale/views/fsm_order.xml b/fieldservice_sale/views/fsm_order.xml new file mode 100644 index 0000000000..4a0de01ae0 --- /dev/null +++ b/fieldservice_sale/views/fsm_order.xml @@ -0,0 +1,19 @@ + + + + fsm.order + + + + + + + + diff --git a/fieldservice_sale/views/product.xml b/fieldservice_sale/views/product.xml new file mode 100644 index 0000000000..d6fd0cea69 --- /dev/null +++ b/fieldservice_sale/views/product.xml @@ -0,0 +1,16 @@ + + + + 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..a23ed15b96 --- /dev/null +++ b/fieldservice_sale/views/sale_order.xml @@ -0,0 +1,23 @@ + + + + sale.order.form.sale.fieldservice + sale.order + + + + + + + + + + + From e8b3830f8e1e23636b7c40daf153b81f36c393e9 Mon Sep 17 00:00:00 2001 From: brian10048 Date: Mon, 13 May 2019 19:19:11 -0400 Subject: [PATCH 09/77] [IMP] fieldservice_sale Added support for selling recurring orders --- fieldservice_sale/__manifest__.py | 2 + fieldservice_sale/models/__init__.py | 1 + fieldservice_sale/models/fsm_recurring.py | 21 ++++ fieldservice_sale/models/product.py | 8 +- fieldservice_sale/models/sale_order.py | 115 +++++++++++++++++++++- fieldservice_sale/views/fsm_recurring.xml | 19 ++++ fieldservice_sale/views/product.xml | 2 + fieldservice_sale/views/sale_order.xml | 13 +++ 8 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 fieldservice_sale/models/fsm_recurring.py create mode 100644 fieldservice_sale/views/fsm_recurring.xml diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 8dee4eb29d..8b03f285ec 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -10,11 +10,13 @@ 'website': 'https://github.com/OCA/field-service', 'depends': [ 'fieldservice', + 'fieldservice_recurring', 'sale_management', ], 'data': [ 'views/fsm_location.xml', 'views/fsm_order.xml', + 'views/fsm_recurring.xml', 'views/product.xml', 'views/sale_order.xml', ], diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py index 360a690640..af7c9764a8 100644 --- a/fieldservice_sale/models/__init__.py +++ b/fieldservice_sale/models/__init__.py @@ -5,3 +5,4 @@ from . import product from . import sale_order from . import fsm_order +from . import fsm_recurring diff --git a/fieldservice_sale/models/fsm_recurring.py b/fieldservice_sale/models/fsm_recurring.py new file mode 100644 index 0000000000..30bca2240d --- /dev/null +++ b/fieldservice_sale/models/fsm_recurring.py @@ -0,0 +1,21 @@ +# Copyright (C) 2019 - TODAY, Brian McMaster, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models, _ + + +class FSMRecurring(models.Model): + _inherit = 'fsm.recurring' + + 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, + "context": {"create": False}, + "name": _("Sales Orders"), + } diff --git a/fieldservice_sale/models/product.py b/fieldservice_sale/models/product.py index 9655b7dc2b..241a3d153c 100644 --- a/fieldservice_sale/models/product.py +++ b/fieldservice_sale/models/product.py @@ -13,14 +13,20 @@ class ProductTemplate(models.Model): field_service_tracking = fields.Selection([ ('no', 'Don\'t create order'), ('order', 'Create a single order'), + ('recurring', 'Create a recurring order') ], string="Field Service Tracking", default="no", help="""On Sales order confirmation, this product can generate a field - service order.""") + service order or field service recurring order.""") fsm_order_template_id = fields.Many2one( 'fsm.template', 'Field Service Order Template', help="Select the field service order template to be created") + fsm_recurring_template_id = fields.Many2one( + 'fsm.recurring', 'Field Service Recurring Template', + help="Select a field service recurring order template to be created") @api.onchange('field_service_tracking') def _onchange_field_service_tracking(self): if self.field_service_tracking != 'order': self.fsm_order_template_id = False + elif self.field_service_tracking != 'recurring': + self.fsm_recurring_template_id = False diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index 46395a3967..a3e37f09d0 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -10,11 +10,20 @@ class SaleOrder(models.Model): fsm_location_id = fields.Many2one( 'fsm.location', string='Service Location', help="SO Lines generating a FSM order will be for this location") + date_fsm_request = fields.Datetime( + string='Requested Service Date', readonly=True, + states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, + copy=False, default=fields.Datetime.now) fsm_order_ids = fields.Many2many( 'fsm.order', compute='_compute_fsm_order_ids', string='Field Service orders associated to this sale') fsm_order_count = fields.Float( string='Field Service Orders', compute='_compute_fsm_order_ids') + fsm_recurring_ids = fields.Many2many( + 'fsm.recurring', compute='_compute_fsm_recurring_ids', + string='Field Service Recurring orders associated to this sale') + fsm_recurring_count = fields.Float( + string='FSM Recurring Orders', compute='_compute_fsm_recurring_ids') @api.multi @api.depends('order_line.product_id') @@ -24,6 +33,14 @@ def _compute_fsm_order_ids(self): ('sale_line_id', 'in', order.order_line.ids)]) order.fsm_order_count = len(order.fsm_order_ids) + @api.multi + @api.depends('order_line.product_id') + def _compute_fsm_recurring_ids(self): + for order in self: + order.fsm_recurring_ids = self.env['fsm.recurring'].search([ + ('sale_line_id', 'in', order.order_line.ids)]) + order.fsm_recurring_count = len(order.fsm_recurring_ids) + @api.multi def action_confirm(self): """ On SO confirmation, some lines generate field service orders. """ @@ -46,6 +63,21 @@ def action_view_fsm_order(self): action = {'type': 'ir.actions.act_window_close'} return action + @api.multi + def action_view_fsm_recurring(self): + fsm_recurrings = self.mapped('fsm_recurring_ids') + action = self.env.ref('fieldservice.action_fsm_recurring').read()[0] + if len(fsm_recurrings) > 1: + action['domain'] = [('id', 'in', fsm_recurrings.ids)] + elif len(fsm_recurrings) == 1: + action['views'] = [(self.env.ref( + 'fieldservice.fsm_recurring_form_view').id, + 'form')] + action['res_id'] = fsm_recurrings.id + else: + action = {'type': 'ir.actions.act_window_close'} + return action + class SaleOrderLine(models.Model): _inherit = "sale.order.line" @@ -53,6 +85,9 @@ class SaleOrderLine(models.Model): fsm_order_id = fields.Many2one( 'fsm.order', 'Order', index=True, help="Field Service Order generated by the sales order item") + fsm_recurring_id = fields.Many2one( + 'fsm.recurring', 'Recurring Order', index=True, + help="Field Service Recurring Order generated by the sale order line") is_field_service = fields.Boolean( "Is a Field Service", compute='_compute_is_field_service', store=True, @@ -86,13 +121,29 @@ def _field_create_fsm_order_prepare_values(self): 'customer_id': self.order_id.partner_id.id, 'location_id': self.order_id.fsm_location_id.id, # 'request_early': , - # 'scheduled_date_start': , + 'scheduled_date_start': self.order_id.date_fsm_request, 'description': self.name, 'template_id': self.product_id.fsm_order_template_id.id, 'sale_line_id': self.id, 'company_id': self.company_id.id, } + def _field_create_fsm_recurring_prepare_values(self): + self.ensure_one() + template = self.product_id.fsm_recurring_template_id + return { + 'customer_id': self.order_id.partner_id.id, + 'location_id': self.order_id.fsm_location_id.id, + 'start_date': self.order_id.date_fsm_request, + 'fsm_recurring_template_id': template.id, + 'description': self.name + '\n ' + template.description, + 'max_orders': template.max_orders, + 'fsm_frequency_set_id': template.fsm_frequency_set_id, + 'fsm_order_template_id': template.fsm_order_template_id, + 'sale_line_id': self.id, + 'company_id': self.company_id.id, + } + @api.multi def _field_create_fsm_order(self): """ Generate fsm_order for the given so line, and link it. @@ -118,10 +169,40 @@ def _field_create_fsm_order(self): """) % (so_line.order_id.id, so_line.order_id.name, so_line.product_id.name) fsm_order.message_post(body=fsm_order_msg) - result[so_line.id] = fsm_order return result + @api.multi + def _field_create_fsm_recurring(self): + """ Generate fsm_recurring for the given so line, and link it. + :return a mapping with the so line id and its linked fsm_recurring + :rtype dict + """ + result = {} + for so_line in self: + # create fsm_recurring + values = so_line._field_create_fsm_recurring_prepare_values() + fsm_recurring = self.env['fsm.recurring'].sudo().create(values) + fsm_recurring.action_start() + so_line.write({'fsm_recurring_id': fsm_recurring.id}) + # post message on SO + msg_body = _( + """Field Service recurring Created (%s): %s + """) % (so_line.product_id.name, + fsm_recurring.id, + fsm_recurring.name) + so_line.order_id.message_post(body=msg_body) + # post message on fsm_recurring + fsm_recurring_msg = _( + """This recurring has been created from: %s (%s) + """) % (so_line.order_id.id, so_line.order_id.name, + so_line.product_id.name) + fsm_recurring.message_post(body=fsm_recurring_msg) + result[so_line.id] = fsm_recurring + return result + @api.multi def _field_find_fsm_order(self): """ Find the fsm_order generated by the so lines. If no fsm_order @@ -134,7 +215,6 @@ def _field_find_fsm_order(self): ('sale_line_id', 'in', self.ids)]) fsm_order_sol_mapping = { fsm_order.sale_line_id.id: fsm_order for fsm_order in fsm_orders} - result = {} for so_line in self: # If the SO was confirmed, cancelled, set to draft then confirmed, @@ -146,6 +226,32 @@ def _field_find_fsm_order(self): result[so_line.id] = fsm_order return result + @api.multi + def _field_find_fsm_recurring(self): + """ Find the fsm_recurring generated by the so lines. If no + fsm_recurring linked, it will be created automatically. + :return a mapping with the so line id and its linked + fsm_recurring + :rtype dict + """ + # one search for all so lines + fsm_recurrings = self.env['fsm.recurring'].search([ + ('sale_line_id', 'in', self.ids)]) + fsm_recurring_sol_mapping = { + fsm_recurring.sale_line_id.id: + fsm_recurring for fsm_recurring in fsm_recurrings} + result = {} + for so_line in self: + # If the SO was confirmed, cancelled, set to draft then confirmed, + # avoid creating a new fsm_recurring. + fsm_recurring = fsm_recurring_sol_mapping.get(so_line.id) + # If not found, create one fsm_recurring for the so line + if not fsm_recurring: + fsm_recurring = so_line._field_create_fsm_recurring( + )[so_line.id] + result[so_line.id] = fsm_recurring + return result + @api.multi def _field_service_generation(self): """ For service lines, create the field service order. If it already @@ -155,3 +261,6 @@ def _field_service_generation(self): # create order if so_line.product_id.field_service_tracking == 'order': so_line._field_find_fsm_order() + # create recurring order + elif so_line.product_id.field_service_tracking == 'recurring': + so_line._field_find_fsm_recurring() diff --git a/fieldservice_sale/views/fsm_recurring.xml b/fieldservice_sale/views/fsm_recurring.xml new file mode 100644 index 0000000000..aedaeb3826 --- /dev/null +++ b/fieldservice_sale/views/fsm_recurring.xml @@ -0,0 +1,19 @@ + + + + fsm.recurring + + + + + + + + diff --git a/fieldservice_sale/views/product.xml b/fieldservice_sale/views/product.xml index d6fd0cea69..1553a6a8fb 100644 --- a/fieldservice_sale/views/product.xml +++ b/fieldservice_sale/views/product.xml @@ -10,6 +10,8 @@ attrs="{'invisible': [('type','!=','service')]}"/> + diff --git a/fieldservice_sale/views/sale_order.xml b/fieldservice_sale/views/sale_order.xml index a23ed15b96..fa3538f07e 100644 --- a/fieldservice_sale/views/sale_order.xml +++ b/fieldservice_sale/views/sale_order.xml @@ -14,10 +14,23 @@ groups="fieldservice.group_fsm_user"> + + + + + + From 4392e0c0b77bb66f451e1311e178dabb139a9b28 Mon Sep 17 00:00:00 2001 From: brian10048 Date: Wed, 22 May 2019 18:35:48 -0400 Subject: [PATCH 10/77] [FIX] fieldservice_sale errors Travis Typo, wrong model relationship Improved values prepation method for recurring Updated errors on SO smart button for recurring --- fieldservice_sale/README.rst | 30 ++++++++++++++----- fieldservice_sale/models/product.py | 2 +- fieldservice_sale/models/sale_order.py | 19 +++++++----- .../static/description/index.html | 26 ++++++++++++++-- fieldservice_sale/views/sale_order.xml | 2 +- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst index 39d9b32177..69e0db232a 100644 --- a/fieldservice_sale/README.rst +++ b/fieldservice_sale/README.rst @@ -38,16 +38,22 @@ Installation To install Field Service and have the mapping features, you need to install GeoEngine. Please refer to the installation instructions available at: -<<<<<<< HEAD https://github.com/OCA/geospatial/tree/12.0/base_geoengine -======= -https://github.com/OCA/geospatial/tree/11.0/base_geoengine ->>>>>>> [UPD] README.rst Configuration ============= -To use this module, you need to: +To setup a product for quoting and selling field service orders: + +* Go to Sales > Catalog > Products +* Create or select a product +* Set the Product Type to 'Service' under General Information tab +* Under Invoicing tab, set the Field Service Tracking option +* 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, you need to: * Go to Field Service > Master Data > Locations * Create or select a location @@ -56,7 +62,12 @@ To use this module, you need to: Usage ===== -Coming soon... +* Go to Sales app +* 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 Known issues / Roadmap ====================== @@ -89,6 +100,8 @@ Contributors * Maxime Chambreuil * Wolfgang Hall * Serpent Consulting Services Pvt. Ltd. +* Brian McMaster + Other credits ~~~~~~~~~~~~~ @@ -116,10 +129,13 @@ promote its widespread use. .. |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-wolfhall| |maintainer-max3903| |maintainer-brian10048| This module is part of the `OCA/field-service `_ project on GitHub. diff --git a/fieldservice_sale/models/product.py b/fieldservice_sale/models/product.py index 241a3d153c..e96a2fbdd7 100644 --- a/fieldservice_sale/models/product.py +++ b/fieldservice_sale/models/product.py @@ -21,7 +21,7 @@ class ProductTemplate(models.Model): 'fsm.template', 'Field Service Order Template', help="Select the field service order template to be created") fsm_recurring_template_id = fields.Many2one( - 'fsm.recurring', 'Field Service Recurring Template', + 'fsm.recurring.template', 'Field Service Recurring Template', help="Select a field service recurring order template to be created") @api.onchange('field_service_tracking') diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index a3e37f09d0..0262d65d0c 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -66,13 +66,15 @@ def action_view_fsm_order(self): @api.multi def action_view_fsm_recurring(self): fsm_recurrings = self.mapped('fsm_recurring_ids') - action = self.env.ref('fieldservice.action_fsm_recurring').read()[0] + action = self.env.ref( + 'fieldservice_recurring.action_fsm_recurring').read()[0] if len(fsm_recurrings) > 1: action['domain'] = [('id', 'in', fsm_recurrings.ids)] elif len(fsm_recurrings) == 1: - action['views'] = [(self.env.ref( - 'fieldservice.fsm_recurring_form_view').id, - 'form')] + action['views'] = [ + (self.env.ref( + 'fieldservice_recurring.fsm_recurring_form_view').id, + 'form')] action['res_id'] = fsm_recurrings.id else: action = {'type': 'ir.actions.act_window_close'} @@ -131,15 +133,18 @@ def _field_create_fsm_order_prepare_values(self): def _field_create_fsm_recurring_prepare_values(self): self.ensure_one() template = self.product_id.fsm_recurring_template_id + note = self.name + if template.description: + note += '\n ' + template.description return { 'customer_id': self.order_id.partner_id.id, 'location_id': self.order_id.fsm_location_id.id, 'start_date': self.order_id.date_fsm_request, 'fsm_recurring_template_id': template.id, - 'description': self.name + '\n ' + template.description, + 'description': note, 'max_orders': template.max_orders, - 'fsm_frequency_set_id': template.fsm_frequency_set_id, - 'fsm_order_template_id': template.fsm_order_template_id, + 'fsm_frequency_set_id': template.fsm_frequency_set_id.id, + 'fsm_order_template_id': template.fsm_order_template_id.id, 'sale_line_id': self.id, 'company_id': self.company_id.id, } diff --git a/fieldservice_sale/static/description/index.html b/fieldservice_sale/static/description/index.html index 23490becee..1daf759a46 100644 --- a/fieldservice_sale/static/description/index.html +++ b/fieldservice_sale/static/description/index.html @@ -394,7 +394,19 @@

    Installation

    Configuration

    -

    To use this module, you need to:

    +

    To setup a product for quoting and selling field service orders:

    +
      +
    • Go to Sales > Catalog > Products
    • +
    • Create or select a product
    • +
    • Set the Product Type to ???Service??? under General Information tab
    • +
    • Under Invoicing tab, set the Field Service Tracking option
    • +
    • +
      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, you need to:

    • Go to Field Service > Master Data > Locations
    • Create or select a location
    • @@ -403,7 +415,14 @@

      Configuration

    Usage

    -

    Coming soon???

    +
      +
    • Go to Sales app
    • +
    • 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
    • +

    Known issues / Roadmap

    @@ -433,6 +452,7 @@

    Contributors

  • Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
  • Wolfgang Hall <whall@opensourceintegrators.com>
  • Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>
  • +
  • Brian McMaster <brian@mcmpest.com>
  • @@ -450,8 +470,10 @@

    Maintainers

    mission is to support the collaborative development of Odoo features and promote its widespread use.

    Current maintainers:

    +<<<<<<< HEAD

    wolfhall max3903

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

    +

    wolfhall max3903 brian10048

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

    diff --git a/fieldservice_sale/views/sale_order.xml b/fieldservice_sale/views/sale_order.xml index fa3538f07e..16d5f6699f 100644 --- a/fieldservice_sale/views/sale_order.xml +++ b/fieldservice_sale/views/sale_order.xml @@ -17,7 +17,7 @@
    - diff --git a/fieldservice_sale/views/product_template.xml b/fieldservice_sale/views/product_template.xml index f7e5e51307..a1da19f361 100644 --- a/fieldservice_sale/views/product_template.xml +++ b/fieldservice_sale/views/product_template.xml @@ -2,12 +2,14 @@ product.template.fieldservice.form product.template - + - - + + diff --git a/fieldservice_sale/views/res_config_settings.xml b/fieldservice_sale/views/res_config_settings.xml index 5ccce52562..61ebb9c951 100644 --- a/fieldservice_sale/views/res_config_settings.xml +++ b/fieldservice_sale/views/res_config_settings.xml @@ -1,12 +1,11 @@ - - + - - - + + + + - diff --git a/fieldservice_sale/views/sale_order.xml b/fieldservice_sale/views/sale_order.xml index ef445200a6..fa628c2f6b 100644 --- a/fieldservice_sale/views/sale_order.xml +++ b/fieldservice_sale/views/sale_order.xml @@ -2,20 +2,26 @@ sale.order.form.sale.fieldservice sale.order - + - - + From 571e22a8c413247616efa80c006998e72faa0474 Mon Sep 17 00:00:00 2001 From: brian10048 Date: Sat, 18 Jul 2020 00:08:36 -0400 Subject: [PATCH 47/77] [MIG] fieldservice_sale: Migration to 13.0 --- fieldservice_sale/__manifest__.py | 2 +- fieldservice_sale/models/sale_order.py | 6 ------ fieldservice_sale/models/sale_order_line.py | 6 ------ fieldservice_sale/readme/INSTALL.rst | 2 +- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 7f47a70077..94b8f9007c 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Field Service - Sales", - "version": "12.0.2.5.1", + "version": "13.0.1.0.0", "summary": "Sell field services.", "category": "Field Service", "author": "Open Source Integrators, Odoo Community Association (OCA)", diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index 571e0317c0..30c06f7e3c 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -22,7 +22,6 @@ class SaleOrder(models.Model): string="FSM Orders", compute="_compute_fsm_order_ids" ) - @api.multi @api.depends("order_line") def _compute_fsm_order_ids(self): for order in self: @@ -79,7 +78,6 @@ def _field_create_fsm_order_prepare_values(self): "company_id": self.company_id.id, } - @api.multi def _field_create_fsm_order(self): """ Generate fsm_order for the given Sale Order, and link it. :return a mapping with the sale order id and its linked fsm_order @@ -113,7 +111,6 @@ def _field_create_fsm_order(self): result[so.id] = fsm_order return result - @api.multi def _field_find_fsm_order(self): """ Find the fsm_order generated by the Sale Order. If no fsm_order linked, it will be created automatically. @@ -138,7 +135,6 @@ def _field_find_fsm_order(self): result[so.id] = fsm_order return result - @api.multi def _action_confirm(self): """ On SO confirmation, some lines generate field service orders. """ result = super(SaleOrder, self)._action_confirm() @@ -150,7 +146,6 @@ def _action_confirm(self): self.order_line._field_service_generation() return result - @api.multi def action_invoice_create(self, grouped=False, final=False): invoice_ids = super().action_invoice_create(grouped, final) result = invoice_ids or [] @@ -205,7 +200,6 @@ def action_invoice_create(self, grouped=False, final=False): result.append(new.id) return result - @api.multi def action_view_fsm_order(self): fsm_orders = self.mapped("fsm_order_ids") action = self.env.ref("fieldservice.action_fsm_dash_order").read()[0] diff --git a/fieldservice_sale/models/sale_order_line.py b/fieldservice_sale/models/sale_order_line.py index cbc793aac6..db320def81 100644 --- a/fieldservice_sale/models/sale_order_line.py +++ b/fieldservice_sale/models/sale_order_line.py @@ -25,7 +25,6 @@ def _compute_product_updatable(self): else: super(SaleOrderLine, line)._compute_product_updatable() - @api.multi @api.depends("product_id") def _compute_qty_delivered_method(self): super(SaleOrderLine, self)._compute_qty_delivered_method() @@ -33,7 +32,6 @@ def _compute_qty_delivered_method(self): if not line.is_expense and line.product_id.field_service_tracking == "line": line.qty_delivered_method = "field_service" - @api.multi @api.depends("fsm_order_id.stage_id") def _compute_qty_delivered(self): super(SaleOrderLine, self)._compute_qty_delivered() @@ -73,7 +71,6 @@ def _field_create_fsm_order_prepare_values(self): "company_id": self.company_id.id, } - @api.multi def _field_create_fsm_order(self): """ Generate fsm_order for the given so line, and link it. :return a mapping with the so line id and its linked fsm_order @@ -108,7 +105,6 @@ def _field_create_fsm_order(self): result[so_line.id] = fsm_order return result - @api.multi def _field_find_fsm_order(self): """ Find the fsm_order generated by the so lines. If no fsm_order linked, it will be created automatically. @@ -132,7 +128,6 @@ def _field_find_fsm_order(self): res[so_line.id] = fsm_order return res - @api.multi def _field_service_generation(self): """ For service lines, create the field service order. If it already exists, it simply links the existing one to the line. @@ -145,7 +140,6 @@ def _field_service_generation(self): if rec.product_id.field_service_tracking == "line": rec._field_find_fsm_order() - @api.multi def _prepare_invoice_line(self, qty): res = super()._prepare_invoice_line(qty) res.update({"fsm_order_id": self.fsm_order_id.id}) diff --git a/fieldservice_sale/readme/INSTALL.rst b/fieldservice_sale/readme/INSTALL.rst index 8571f65376..e5355c4b0f 100644 --- a/fieldservice_sale/readme/INSTALL.rst +++ b/fieldservice_sale/readme/INSTALL.rst @@ -1,4 +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/12.0/base_geoengine +https://github.com/OCA/geospatial/tree/13.0/base_geoengine From 9a610c0ba755677326f0b7c8f07d3418b0f65040 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 5 Oct 2020 16:31:29 -0700 Subject: [PATCH 48/77] [FIX] fieldservice_sale migration changes --- fieldservice_sale/__manifest__.py | 2 +- fieldservice_sale/models/__init__.py | 2 +- fieldservice_sale/models/fsm_location.py | 2 +- .../models/{fsm_branch.py => res_branch.py} | 4 ++-- fieldservice_sale/readme/CONTRIBUTORS.rst | 1 + fieldservice_sale/views/fsm_branch.xml | 12 ------------ fieldservice_sale/views/res_branch.xml | 12 ++++++++++++ fieldservice_sale/views/res_config_settings.xml | 3 --- 8 files changed, 18 insertions(+), 20 deletions(-) rename fieldservice_sale/models/{fsm_branch.py => res_branch.py} (84%) delete mode 100644 fieldservice_sale/views/fsm_branch.xml create mode 100644 fieldservice_sale/views/res_branch.xml diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 94b8f9007c..1659be6b22 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -10,10 +10,10 @@ "depends": ["fieldservice", "sale_management", "fieldservice_account"], "data": [ "security/ir.model.access.csv", - "views/fsm_branch.xml", "views/fsm_location.xml", "views/fsm_order.xml", "views/product_template.xml", + "views/res_branch.xml", "views/sale_order.xml", "views/res_config_settings.xml", ], diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py index fda80ebcfa..dfe9d6412e 100644 --- a/fieldservice_sale/models/__init__.py +++ b/fieldservice_sale/models/__init__.py @@ -2,10 +2,10 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import ( - fsm_branch, fsm_location, fsm_order, product_template, + res_branch, sale_order_line, sale_order, ) diff --git a/fieldservice_sale/models/fsm_location.py b/fieldservice_sale/models/fsm_location.py index eb1d302ae0..be5cb6f85f 100644 --- a/fieldservice_sale/models/fsm_location.py +++ b/fieldservice_sale/models/fsm_location.py @@ -6,4 +6,4 @@ class FSMLocation(models.Model): _inherit = "fsm.location" - sales_territory_id = fields.Many2one("fsm.territory", string="Sales Territory") + sales_territory_id = fields.Many2one("res.territory", string="Sales Territory") diff --git a/fieldservice_sale/models/fsm_branch.py b/fieldservice_sale/models/res_branch.py similarity index 84% rename from fieldservice_sale/models/fsm_branch.py rename to fieldservice_sale/models/res_branch.py index a8fadfee49..e9a601932e 100644 --- a/fieldservice_sale/models/fsm_branch.py +++ b/fieldservice_sale/models/res_branch.py @@ -3,8 +3,8 @@ from odoo import fields, models -class FSMBranch(models.Model): - _inherit = "fsm.branch" +class ResBranch(models.Model): + _inherit = "res.branch" pricelist_id = fields.Many2one( "product.pricelist", diff --git a/fieldservice_sale/readme/CONTRIBUTORS.rst b/fieldservice_sale/readme/CONTRIBUTORS.rst index 44ba2fbfcb..674036d84b 100644 --- a/fieldservice_sale/readme/CONTRIBUTORS.rst +++ b/fieldservice_sale/readme/CONTRIBUTORS.rst @@ -3,6 +3,7 @@ * Steve Campbell * Maxime Chambreuil * Wolfgang Hall + * Raphael Lee * Serpent Consulting Services Pvt. Ltd. * Brian McMaster diff --git a/fieldservice_sale/views/fsm_branch.xml b/fieldservice_sale/views/fsm_branch.xml deleted file mode 100644 index 6f46faa6a1..0000000000 --- a/fieldservice_sale/views/fsm_branch.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - fsm.branch.form.pricelist - fsm.branch - - - - - - - - diff --git a/fieldservice_sale/views/res_branch.xml b/fieldservice_sale/views/res_branch.xml new file mode 100644 index 0000000000..9629a57a15 --- /dev/null +++ b/fieldservice_sale/views/res_branch.xml @@ -0,0 +1,12 @@ + + + res.branch.form.pricelist + res.branch + + + + + + + + diff --git a/fieldservice_sale/views/res_config_settings.xml b/fieldservice_sale/views/res_config_settings.xml index 61ebb9c951..7d57014d73 100644 --- a/fieldservice_sale/views/res_config_settings.xml +++ b/fieldservice_sale/views/res_config_settings.xml @@ -3,9 +3,6 @@ - - - From 79839bc3071839c46d5dd9d9579f6debbfb388eb Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 7 Oct 2020 15:08:23 -0700 Subject: [PATCH 49/77] [FIX] invoice creation from SO --- .../migrations/12.0.2.0.0/pre-migration.py | 12 ---- fieldservice_sale/models/sale_order.py | 72 ++++++++++++++----- fieldservice_sale/models/sale_order_line.py | 1 - .../tests/test_fsm_sale_order.py | 18 ++--- 4 files changed, 60 insertions(+), 43 deletions(-) delete mode 100644 fieldservice_sale/migrations/12.0.2.0.0/pre-migration.py diff --git a/fieldservice_sale/migrations/12.0.2.0.0/pre-migration.py b/fieldservice_sale/migrations/12.0.2.0.0/pre-migration.py deleted file mode 100644 index 3a7530b375..0000000000 --- a/fieldservice_sale/migrations/12.0.2.0.0/pre-migration.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (C) 2019, Open Source Integrators -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -def migrate(env, version): - if not version: - return - - env.execute( - "UPDATE product_template SET field_service_tracking = 'sale' " - "WHERE field_service_tracking = 'order';" - ) diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index 30c06f7e3c..720963f4e7 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -146,58 +146,92 @@ def _action_confirm(self): self.order_line._field_service_generation() return result - def action_invoice_create(self, grouped=False, final=False): - invoice_ids = super().action_invoice_create(grouped, final) - result = invoice_ids or [] + def _create_invoices(self, grouped=False, final=False): + Invoices = self.env["account.move"] + InvoiceLines = self.env["account.move.line"] + invoice_ids = super()._create_invoices(grouped, final) + result = invoice_ids or Invoices - for invoice_id in invoice_ids: - invoice = self.env["account.invoice"].browse(invoice_id) + for invoice in invoice_ids: # check for invoice lines with product # field_service_tracking = line - lines_by_line = self.env["account.invoice.line"].search( + lines_by_line = InvoiceLines.search( [ - ("invoice_id", "=", invoice_id), + ("move_id", "=", invoice.id), ("product_id.field_service_tracking", "=", "line"), + ("exclude_from_invoice_tab", "=", False), ] ) if len(lines_by_line) > 0: + # Create a new invoice for each "line" product line_count = len(invoice.invoice_line_ids) for i in range(len(lines_by_line)): duplicate = True if ((i + 1) == len(lines_by_line)) and ((i + 1) == line_count): + # Don't create a new invoice if there's only 1 product duplicate = False inv = invoice if duplicate: inv = invoice.copy() - inv.write({"invoice_line_ids": [(6, 0, [])]}) - inv.compute_taxes() - invoice.compute_taxes() - lines_by_line[i].invoice_id = inv.id - result.append(inv.id) + inv.with_context(check_move_validity=False).write( + {'invoice_line_ids': [(6, 0, [])]} + ) + lines_by_line[i].with_context( + check_move_validity=False + ).move_id = inv.id + inv.with_context( + check_move_validity=False + )._recompute_dynamic_lines( + recompute_all_taxes=True, recompute_tax_base_amount=True + ) + invoice.with_context( + check_move_validity=False + )._recompute_dynamic_lines( + recompute_all_taxes=True, recompute_tax_base_amount=True + ) + result |= inv inv.fsm_order_ids = [(4, lines_by_line[i].fsm_order_id.id)] # check for invoice lines with product # field_service_tracking = sale - lines_by_sale = self.env["account.invoice.line"].search( + lines_by_sale = InvoiceLines.search( [ - ("invoice_id", "=", invoice_id), + ("move_id", "=", invoice.id), ("product_id.field_service_tracking", "=", "sale"), + ("exclude_from_invoice_tab", "=", False), ] ) if len(lines_by_sale) > 0: + # Create a new invoice for "sale" products fsm_orders = self.env["fsm.order"].search( [("sale_id", "in", self.ids), ("sale_line_id", "=", False)] ) if len(lines_by_sale) == len(invoice.invoice_line_ids): + # Don't create a new invoice if all products are "sale" invoice.fsm_order_ids = [ (4, fsm_order.id) for fsm_order in fsm_orders ] elif len(invoice.invoice_line_ids) > len(lines_by_sale): new = invoice.copy() - new.write({"invoice_line_ids": [(6, 0, [])]}) - lines_by_sale.write({"invoice_id": new.id}) - new.compute_taxes() - invoice.compute_taxes() - result.append(new.id) + new.fsm_order_ids = [ + (4, fsm_order.id) for fsm_order in fsm_orders + ] + new.with_context(check_move_validity=False).write( + {'invoice_line_ids': [(6, 0, [])]} + ) + lines_by_sale.with_context(check_move_validity=False).write( + {'move_id': new.id} + ) + new.with_context( + check_move_validity=False + )._recompute_dynamic_lines( + recompute_all_taxes=True, recompute_tax_base_amount=True + ) + invoice.with_context( + check_move_validity=False + )._recompute_dynamic_lines( + recompute_all_taxes=True, recompute_tax_base_amount=True + ) + result |= new return result def action_view_fsm_order(self): diff --git a/fieldservice_sale/models/sale_order_line.py b/fieldservice_sale/models/sale_order_line.py index db320def81..a6274407ac 100644 --- a/fieldservice_sale/models/sale_order_line.py +++ b/fieldservice_sale/models/sale_order_line.py @@ -56,7 +56,6 @@ def _field_create_fsm_order_prepare_values(self): self.ensure_one() categories = self.product_id.fsm_order_template_id.category_ids return { - "customer_id": self.order_id.partner_id.id, "location_id": self.order_id.fsm_location_id.id, "location_directions": self.order_id.fsm_location_id.direction, "request_early": self.order_id.expected_date, diff --git a/fieldservice_sale/tests/test_fsm_sale_order.py b/fieldservice_sale/tests/test_fsm_sale_order.py index c74fc5b549..6251154a43 100644 --- a/fieldservice_sale/tests/test_fsm_sale_order.py +++ b/fieldservice_sale/tests/test_fsm_sale_order.py @@ -207,9 +207,8 @@ def test_sale_order_1(self): fsm_order.action_complete() # Invoice the order - Invoice = self.env["account.invoice"] - inv_id = self.sale_order_1.action_invoice_create() - invoice = Invoice.browse(inv_id) + Invoice = self.env["account.move"] + 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" @@ -256,9 +255,8 @@ def test_sale_order_2(self): ) # Invoice the order - Invoice = self.env["account.invoice"] - inv_id = self.sale_order_2.action_invoice_create() - invoice = Invoice.browse(inv_id) + Invoice = self.env["account.move"] + 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" @@ -321,8 +319,7 @@ def test_sale_order_3(self): # Invoice the sale order Invoice = self.env["account.invoice"] - inv_id = self.sale_order_3.action_invoice_create() - invoices = Invoice.browse(inv_id) + invoices = self.sale_order_3._create_invoices() # 2 invoices created self.assertEqual( len(invoices.ids), 2, "FSM Sale: Sale Order 3 should create 2 invoices" @@ -409,9 +406,8 @@ def test_sale_order_4(self): # qty_delivered does not update for FSM orders linked only to the sale # Invoice the sale order - Invoice = self.env["account.invoice"] - inv_id = self.sale_order_4.action_invoice_create() - invoices = Invoice.browse(inv_id) + Invoice = self.env["account.move"] + invoices = self.sale_order_4._create_invoices() # 3 invoices created self.assertEqual( len(invoices.ids), 3, "FSM Sale: Sale Order 4 should create 3 invoices" From 8a63d02c18f4e47311bbd229e10d31406261ad04 Mon Sep 17 00:00:00 2001 From: Brian McMaster Date: Thu, 22 Oct 2020 16:22:50 -0400 Subject: [PATCH 50/77] [IMP] pre-commit, black --- fieldservice_sale/models/sale_order.py | 24 +++++----- .../tests/test_fsm_sale_order.py | 46 +++++++++---------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index 720963f4e7..a52b37a67f 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -79,9 +79,9 @@ def _field_create_fsm_order_prepare_values(self): } def _field_create_fsm_order(self): - """ Generate fsm_order for the given Sale Order, and link it. - :return a mapping with the sale order id and its linked fsm_order - :rtype dict + """Generate fsm_order for the given Sale Order, and link it. + :return a mapping with the sale order id and its linked fsm_order + :rtype dict """ result = {} for so in self: @@ -112,10 +112,10 @@ def _field_create_fsm_order(self): return result def _field_find_fsm_order(self): - """ Find the fsm_order generated by the Sale Order. If no fsm_order - linked, it will be created automatically. - :return a mapping with the so line id and its linked fsm_order - :rtype dict + """Find the fsm_order generated by the Sale Order. If no fsm_order + linked, it will be created automatically. + :return a mapping with the so line id and its linked fsm_order + :rtype dict """ # one search for all Sale Orders fsm_orders = self.env["fsm.order"].search( @@ -174,7 +174,7 @@ def _create_invoices(self, grouped=False, final=False): if duplicate: inv = invoice.copy() inv.with_context(check_move_validity=False).write( - {'invoice_line_ids': [(6, 0, [])]} + {"invoice_line_ids": [(6, 0, [])]} ) lines_by_line[i].with_context( check_move_validity=False @@ -212,14 +212,12 @@ def _create_invoices(self, grouped=False, final=False): ] elif len(invoice.invoice_line_ids) > len(lines_by_sale): new = invoice.copy() - new.fsm_order_ids = [ - (4, fsm_order.id) for fsm_order in fsm_orders - ] + new.fsm_order_ids = [(4, fsm_order.id) for fsm_order in fsm_orders] new.with_context(check_move_validity=False).write( - {'invoice_line_ids': [(6, 0, [])]} + {"invoice_line_ids": [(6, 0, [])]} ) lines_by_sale.with_context(check_move_validity=False).write( - {'move_id': new.id} + {"move_id": new.id} ) new.with_context( check_move_validity=False diff --git a/fieldservice_sale/tests/test_fsm_sale_order.py b/fieldservice_sale/tests/test_fsm_sale_order.py index 6251154a43..f04dd0a29b 100644 --- a/fieldservice_sale/tests/test_fsm_sale_order.py +++ b/fieldservice_sale/tests/test_fsm_sale_order.py @@ -143,9 +143,9 @@ def setUpClass(cls): ) 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 + """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( @@ -156,9 +156,9 @@ def _isp_account_installed(self): 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 + """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 @@ -177,9 +177,9 @@ def _fulfill_order(self, order): return order 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. + """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() @@ -207,7 +207,6 @@ def test_sale_order_1(self): fsm_order.action_complete() # Invoice the order - Invoice = self.env["account.move"] invoice = self.sale_order_1._create_invoices() # 1 invoices created self.assertEqual( @@ -219,10 +218,10 @@ def test_sale_order_1(self): ) 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. + """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 @@ -255,7 +254,6 @@ def test_sale_order_2(self): ) # Invoice the order - Invoice = self.env["account.move"] invoice = self.sale_order_2._create_invoices() # 1 invoice created self.assertEqual( @@ -267,10 +265,10 @@ def test_sale_order_2(self): ) 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. + """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 @@ -318,7 +316,6 @@ def test_sale_order_3(self): ) # Invoice the sale order - Invoice = self.env["account.invoice"] invoices = self.sale_order_3._create_invoices() # 2 invoices created self.assertEqual( @@ -337,10 +334,10 @@ def test_sale_order_3(self): ) 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. - - Three Invoices should be created (One for each FSM Order). + """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. + - Three Invoices should be created (One for each FSM Order). """ sol1 = self.sol_service_per_line_4 sol2 = self.sol_service_per_line_5 @@ -406,7 +403,6 @@ def test_sale_order_4(self): # qty_delivered does not update for FSM orders linked only to the sale # Invoice the sale order - Invoice = self.env["account.move"] invoices = self.sale_order_4._create_invoices() # 3 invoices created self.assertEqual( From 732eeda762c62f0764e1f9c7c106ab2aa7896e1a Mon Sep 17 00:00:00 2001 From: Freni-OSI Date: Thu, 15 Apr 2021 13:45:46 +0530 Subject: [PATCH 51/77] [FIX] Travis --- fieldservice_sale/__manifest__.py | 2 +- fieldservice_sale/models/sale_order_line.py | 18 +++++++++--------- .../tests/test_fsm_sale_onchange_partner.py | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index 1659be6b22..94495b6413 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Field Service - Sales", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "summary": "Sell field services.", "category": "Field Service", "author": "Open Source Integrators, Odoo Community Association (OCA)", diff --git a/fieldservice_sale/models/sale_order_line.py b/fieldservice_sale/models/sale_order_line.py index a6274407ac..4c7c4bccc4 100644 --- a/fieldservice_sale/models/sale_order_line.py +++ b/fieldservice_sale/models/sale_order_line.py @@ -71,9 +71,9 @@ def _field_create_fsm_order_prepare_values(self): } def _field_create_fsm_order(self): - """ Generate fsm_order for the given so line, and link it. - :return a mapping with the so line id and its linked fsm_order - :rtype dict + """Generate fsm_order for the given so line, and link it. + :return a mapping with the so line id and its linked fsm_order + :rtype dict """ result = {} for so_line in self: @@ -105,10 +105,10 @@ def _field_create_fsm_order(self): return result def _field_find_fsm_order(self): - """ Find the fsm_order generated by the so lines. If no fsm_order - linked, it will be created automatically. - :return a mapping with the so line id and its linked fsm_order - :rtype dict + """Find the fsm_order generated by the so lines. If no fsm_order + linked, it will be created automatically. + :return a mapping with the so line id and its linked fsm_order + :rtype dict """ for rec in self: # one search for all so lines @@ -128,8 +128,8 @@ def _field_find_fsm_order(self): return res def _field_service_generation(self): - """ For service lines, create the field service order. If it already - exists, it simply links the existing one to the line. + """For service lines, create the field service order. If it already + exists, it simply links the existing one to the line. """ for rec in self: if rec.product_id.field_service_tracking == "sale": diff --git a/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py b/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py index a856900b04..9c66f21fa2 100644 --- a/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py +++ b/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py @@ -34,7 +34,7 @@ def setUp(self): self.location = self.env.ref("fieldservice.location_1") def test_1_autofill_so_fsm_location(self): - """ First case : + """First case : - commercial_partner IS NOT a fsm_location - partner IS a fsm_location - shipping_partner IS NOT a fsm_location @@ -49,7 +49,7 @@ def test_1_autofill_so_fsm_location(self): self.assertEqual(self.so.fsm_location_id.id, self.location.id) def test_2_autofill_so_fsm_location(self): - """ Second case : + """Second case : - commercial_partner IS NOT a fsm_location - partner IS NOT a fsm_location - shipping_partner IS a fsm_location @@ -64,7 +64,7 @@ def test_2_autofill_so_fsm_location(self): self.assertEqual(self.so.fsm_location_id.id, self.location.id) def test_3_autofill_so_fsm_location(self): - """ Third case : + """Third case : - commercial_partner IS a fsm_location - partner IS NOT a fsm_location - shipping_partner IS NOT a fsm_location From 3232d2e987d0dc5c5473d9886cbefdd904c325da Mon Sep 17 00:00:00 2001 From: Freni-OSI Date: Thu, 15 Apr 2021 14:48:53 +0530 Subject: [PATCH 52/77] [14.0][MIG] fieldservice_sale --- fieldservice_sale/README.rst | 13 +- fieldservice_sale/__manifest__.py | 13 +- fieldservice_sale/i18n/fieldservice_sale.pot | 131 +- .../migrations/14.0.1.0.0/pre-migration.py | 12 + fieldservice_sale/models/__init__.py | 2 - fieldservice_sale/models/fsm_location.py | 9 - fieldservice_sale/models/product_template.py | 8 +- fieldservice_sale/models/res_branch.py | 13 - fieldservice_sale/models/sale_order.py | 88 +- fieldservice_sale/models/sale_order_line.py | 16 +- .../static/description/index.html | 1264 ++++++----------- fieldservice_sale/tests/__init__.py | 4 +- .../tests/test_fsm_sale_common.py | 13 +- .../tests/test_fsm_sale_onchange_partner.py | 12 +- .../tests/test_fsm_sale_order.py | 66 +- fieldservice_sale/views/fsm_location.xml | 2 +- fieldservice_sale/views/fsm_order.xml | 2 + fieldservice_sale/views/res_branch.xml | 12 - .../views/res_config_settings.xml | 5 +- 19 files changed, 635 insertions(+), 1050 deletions(-) create mode 100644 fieldservice_sale/migrations/14.0.1.0.0/pre-migration.py delete mode 100644 fieldservice_sale/models/fsm_location.py delete mode 100644 fieldservice_sale/models/res_branch.py delete mode 100644 fieldservice_sale/views/res_branch.xml diff --git a/fieldservice_sale/README.rst b/fieldservice_sale/README.rst index 5d2e317105..adc633e26c 100644 --- a/fieldservice_sale/README.rst +++ b/fieldservice_sale/README.rst @@ -14,13 +14,13 @@ Field Service - Sales :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/12.0/fieldservice_sale + :target: https://github.com/OCA/field-service/tree/14.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-12-0/field-service-12-0-fieldservice_sale + :target: https://translation.odoo-community.org/projects/field-service-14-0/field-service-14-0-fieldservice_sale :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/264/12.0 + :target: https://runbot.odoo-community.org/runbot/264/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -39,7 +39,7 @@ 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/12.0/base_geoengine +https://github.com/OCA/geospatial/tree/13.0/base_geoengine Configuration ============= @@ -99,7 +99,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -119,6 +119,7 @@ Contributors * Steve Campbell * Maxime Chambreuil * Wolfgang Hall + * Raphael Lee * Serpent Consulting Services Pvt. Ltd. * Brian McMaster @@ -152,6 +153,6 @@ Current `maintainers `__: |maintainer-wolfhall| |maintainer-max3903| |maintainer-brian10048| -This module is part of the `OCA/field-service `_ project on GitHub. +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/__manifest__.py b/fieldservice_sale/__manifest__.py index 94495b6413..aeade35e98 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -7,18 +7,25 @@ "category": "Field Service", "author": "Open Source Integrators, Odoo Community Association (OCA)", "website": "https://github.com/OCA/field-service", - "depends": ["fieldservice", "sale_management", "fieldservice_account"], + "depends": [ + "fieldservice", + "sale_management", + "fieldservice_account", + ], "data": [ "security/ir.model.access.csv", "views/fsm_location.xml", "views/fsm_order.xml", "views/product_template.xml", - "views/res_branch.xml", "views/sale_order.xml", "views/res_config_settings.xml", ], "license": "AGPL-3", "development_status": "Beta", - "maintainers": ["wolfhall", "max3903", "brian10048"], + "maintainers": [ + "wolfhall", + "max3903", + "brian10048", + ], "installable": True, } diff --git a/fieldservice_sale/i18n/fieldservice_sale.pot b/fieldservice_sale/i18n/fieldservice_sale.pot index 9326106b9a..8737075df8 100644 --- a/fieldservice_sale/i18n/fieldservice_sale.pot +++ b/fieldservice_sale/i18n/fieldservice_sale.pot @@ -1,12 +1,12 @@ # Translation of Odoo Server. # This file contains the translation of the following modules: -# * fieldservice_sale +# * fieldservice_sale # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" +"Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: <>\n" +"Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -20,48 +20,29 @@ 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" +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 -#: selection:sale.order.line,qty_delivered_method:0 -msgid "Analytic From Expenses" -msgstr "" - -#. module: fieldservice_sale -#: selection:product.template,field_service_tracking:0 -msgid "Create a recurring order" msgstr "" #. module: fieldservice_sale -#: selection:product.template,field_service_tracking:0 +#: 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 -#: selection:product.template,field_service_tracking:0 +#: 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,field_description:fieldservice_sale.field_fsm_branch__pricelist_id -msgid "Default Pricelist" -msgstr "" - -#. module: fieldservice_sale -#: model:ir.model.fields,help:fieldservice_sale.field_fsm_branch__pricelist_id -msgid "Default pricelist for new customers of this branch." -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" +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" @@ -69,12 +50,19 @@ msgid "Determines what happens upon sale order confirmation:\n" msgstr "" #. module: fieldservice_sale -#: selection:product.template,field_service_tracking:0 +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__display_name +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__display_name +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__display_name +msgid "Display Name" +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:131 +#: code:addons/fieldservice_sale/models/sale_order.py:0 #, python-format msgid "FSM Location must be set" msgstr "" @@ -85,29 +73,26 @@ msgstr "" msgid "FSM Orders" msgstr "" -#. module: fieldservice_sale -#: model:ir.model,name:fieldservice_sale.model_fsm_location -msgid "Field Service Location" -msgstr "" - #. module: fieldservice_sale #: model:ir.model,name:fieldservice_sale.model_fsm_order -#: selection:sale.order.line,qty_delivered_method:0 +#: 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 -#: code:addons/fieldservice_sale/models/sale_order_line.py:87 +#: code:addons/fieldservice_sale/models/sale_order_line.py:0 #, python-format -msgid "Field Service Order Created (%s): %s\n" " " msgstr "" #. module: fieldservice_sale -#: code:addons/fieldservice_sale/models/sale_order.py:86 +#: code:addons/fieldservice_sale/models/sale_order.py:0 #, python-format -msgid "Field Service Order Created: %s\n" " " msgstr "" @@ -124,7 +109,7 @@ msgid "Field Service Order generated by the sales order item" msgstr "" #. module: fieldservice_sale -#: selection:product.template,service_type:0 +#: model:ir.model.fields.selection,name:fieldservice_sale.selection__product_template__service_type__field msgid "Field Service Orders" msgstr "" @@ -140,19 +125,26 @@ msgid "Field Service orders associated to this sale" msgstr "" #. module: fieldservice_sale -#: selection:sale.order.line,qty_delivered_method:0 -msgid "Manual" +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__id +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template__id +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order__id +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__id +msgid "ID" msgstr "" #. module: fieldservice_sale -#: selection:product.template,service_type:0 -msgid "Manually set quantities on order" +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order____last_update +#: model:ir.model.fields,field_description:fieldservice_sale.field_product_template____last_update +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order____last_update +#: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line____last_update +msgid "Last Modified on" 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" +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 "" @@ -163,6 +155,7 @@ msgid "Method to update delivered qty" msgstr "" #. module: fieldservice_sale +#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_order__display_name #: model:ir.model.fields,field_description:fieldservice_sale.field_sale_order_line__fsm_order_id msgid "Order" msgstr "" @@ -188,13 +181,13 @@ msgid "Sale Line" msgstr "" #. module: fieldservice_sale -#: model:ir.model,name:fieldservice_sale.model_sale_order -msgid "Sale Order" +#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view +msgid "Sales" msgstr "" #. module: fieldservice_sale -#: model_terms:ir.ui.view,arch_db:fieldservice_sale.fsm_location_form_view -msgid "Sales" +#: model:ir.model,name:fieldservice_sale.model_sale_order +msgid "Sales Order" msgstr "" #. module: fieldservice_sale @@ -203,16 +196,11 @@ msgid "Sales Order Line" msgstr "" #. module: fieldservice_sale -#: code:addons/fieldservice_sale/models/fsm_order.py:21 +#: code:addons/fieldservice_sale/models/fsm_order.py:0 #, python-format msgid "Sales Orders" msgstr "" -#. module: fieldservice_sale -#: model:ir.model.fields,field_description:fieldservice_sale.field_fsm_location__sales_territory_id -msgid "Sales Territory" -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 @@ -225,44 +213,25 @@ msgid "Service Location" msgstr "" #. module: fieldservice_sale -#: selection:sale.order.line,qty_delivered_method:0 -msgid "Stock Moves" -msgstr "" - -#. module: fieldservice_sale -#: code:addons/fieldservice_sale/models/sale_order.py:92 +#: code:addons/fieldservice_sale/models/sale_order.py:0 #, python-format -msgid "This order has been created from: %s\n" " " msgstr "" #. module: fieldservice_sale -#: code:addons/fieldservice_sale/models/sale_order_line.py:93 +#: code:addons/fieldservice_sale/models/sale_order_line.py:0 #, python-format -msgid "This order has been created from: %s (%s)\n" " " msgstr "" -#. module: fieldservice_sale -#: selection:sale.order.line,qty_delivered_method:0 -msgid "Timesheets" -msgstr "" - -#. module: fieldservice_sale -#: selection:product.template,service_type:0 -msgid "Timesheets on project (one fare per SO/Project)" -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 "" - -#. module: fieldservice_sale -#: model:ir.model,name:fieldservice_sale.model_fsm_branch -msgid "branch" -msgstr "" - diff --git a/fieldservice_sale/migrations/14.0.1.0.0/pre-migration.py b/fieldservice_sale/migrations/14.0.1.0.0/pre-migration.py new file mode 100644 index 0000000000..786eb40ee3 --- /dev/null +++ b/fieldservice_sale/migrations/14.0.1.0.0/pre-migration.py @@ -0,0 +1,12 @@ +# Copyright (C) 2021, Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +def migrate(env, version): + if not version: + return + + env.execute( + "UPDATE product_template SET field_service_tracking = 'sale' " + "WHERE field_service_tracking = 'order';" + ) diff --git a/fieldservice_sale/models/__init__.py b/fieldservice_sale/models/__init__.py index dfe9d6412e..dad9bb704f 100644 --- a/fieldservice_sale/models/__init__.py +++ b/fieldservice_sale/models/__init__.py @@ -2,10 +2,8 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import ( - fsm_location, fsm_order, product_template, - res_branch, sale_order_line, sale_order, ) diff --git a/fieldservice_sale/models/fsm_location.py b/fieldservice_sale/models/fsm_location.py deleted file mode 100644 index be5cb6f85f..0000000000 --- a/fieldservice_sale/models/fsm_location.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) 2018 Open Source Integrators -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models - - -class FSMLocation(models.Model): - _inherit = "fsm.location" - - sales_territory_id = fields.Many2one("res.territory", string="Sales Territory") diff --git a/fieldservice_sale/models/product_template.py b/fieldservice_sale/models/product_template.py index 67124ddf8c..0570db0606 100644 --- a/fieldservice_sale/models/product_template.py +++ b/fieldservice_sale/models/product_template.py @@ -1,13 +1,19 @@ # 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")]) + service_type = fields.Selection( + selection_add=[ + ("field", "Field Service Orders"), + ], + ondelete={"field": "cascade"}, + ) field_service_tracking = fields.Selection( [ ("no", "Don't create FSM order"), diff --git a/fieldservice_sale/models/res_branch.py b/fieldservice_sale/models/res_branch.py deleted file mode 100644 index e9a601932e..0000000000 --- a/fieldservice_sale/models/res_branch.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (C) 2020 Open Source Integrators -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models - - -class ResBranch(models.Model): - _inherit = "res.branch" - - pricelist_id = fields.Many2one( - "product.pricelist", - string="Default Pricelist", - help="Default pricelist for new customers of this branch.", - ) diff --git a/fieldservice_sale/models/sale_order.py b/fieldservice_sale/models/sale_order.py index a52b37a67f..899346cc1a 100644 --- a/fieldservice_sale/models/sale_order.py +++ b/fieldservice_sale/models/sale_order.py @@ -64,7 +64,7 @@ def _field_create_fsm_order_prepare_values(self): categories = self.env["fsm.category"] for template in templates: note += template.instructions or "" - hours += template.hours + hours += template.duration categories |= template.category_ids return { "location_id": self.fsm_location_id.id, @@ -146,92 +146,6 @@ def _action_confirm(self): self.order_line._field_service_generation() return result - def _create_invoices(self, grouped=False, final=False): - Invoices = self.env["account.move"] - InvoiceLines = self.env["account.move.line"] - invoice_ids = super()._create_invoices(grouped, final) - result = invoice_ids or Invoices - - for invoice in invoice_ids: - # check for invoice lines with product - # field_service_tracking = line - lines_by_line = InvoiceLines.search( - [ - ("move_id", "=", invoice.id), - ("product_id.field_service_tracking", "=", "line"), - ("exclude_from_invoice_tab", "=", False), - ] - ) - if len(lines_by_line) > 0: - # Create a new invoice for each "line" product - line_count = len(invoice.invoice_line_ids) - for i in range(len(lines_by_line)): - duplicate = True - if ((i + 1) == len(lines_by_line)) and ((i + 1) == line_count): - # Don't create a new invoice if there's only 1 product - duplicate = False - inv = invoice - if duplicate: - inv = invoice.copy() - inv.with_context(check_move_validity=False).write( - {"invoice_line_ids": [(6, 0, [])]} - ) - lines_by_line[i].with_context( - check_move_validity=False - ).move_id = inv.id - inv.with_context( - check_move_validity=False - )._recompute_dynamic_lines( - recompute_all_taxes=True, recompute_tax_base_amount=True - ) - invoice.with_context( - check_move_validity=False - )._recompute_dynamic_lines( - recompute_all_taxes=True, recompute_tax_base_amount=True - ) - result |= inv - inv.fsm_order_ids = [(4, lines_by_line[i].fsm_order_id.id)] - # check for invoice lines with product - # field_service_tracking = sale - lines_by_sale = InvoiceLines.search( - [ - ("move_id", "=", invoice.id), - ("product_id.field_service_tracking", "=", "sale"), - ("exclude_from_invoice_tab", "=", False), - ] - ) - if len(lines_by_sale) > 0: - # Create a new invoice for "sale" products - fsm_orders = self.env["fsm.order"].search( - [("sale_id", "in", self.ids), ("sale_line_id", "=", False)] - ) - if len(lines_by_sale) == len(invoice.invoice_line_ids): - # Don't create a new invoice if all products are "sale" - invoice.fsm_order_ids = [ - (4, fsm_order.id) for fsm_order in fsm_orders - ] - elif len(invoice.invoice_line_ids) > len(lines_by_sale): - new = invoice.copy() - new.fsm_order_ids = [(4, fsm_order.id) for fsm_order in fsm_orders] - new.with_context(check_move_validity=False).write( - {"invoice_line_ids": [(6, 0, [])]} - ) - lines_by_sale.with_context(check_move_validity=False).write( - {"move_id": new.id} - ) - new.with_context( - check_move_validity=False - )._recompute_dynamic_lines( - recompute_all_taxes=True, recompute_tax_base_amount=True - ) - invoice.with_context( - check_move_validity=False - )._recompute_dynamic_lines( - recompute_all_taxes=True, recompute_tax_base_amount=True - ) - result |= new - return result - def action_view_fsm_order(self): fsm_orders = self.mapped("fsm_order_ids") action = self.env.ref("fieldservice.action_fsm_dash_order").read()[0] diff --git a/fieldservice_sale/models/sale_order_line.py b/fieldservice_sale/models/sale_order_line.py index 4c7c4bccc4..ff40c3b9c0 100644 --- a/fieldservice_sale/models/sale_order_line.py +++ b/fieldservice_sale/models/sale_order_line.py @@ -8,7 +8,8 @@ class SaleOrderLine(models.Model): _inherit = "sale.order.line" qty_delivered_method = fields.Selection( - selection_add=[("field_service", "Field Service Order")] + selection_add=[("field_service", "Field Service Order")], + ondelete={"field_service": "cascade"}, ) fsm_order_id = fields.Many2one( "fsm.order", @@ -64,7 +65,7 @@ def _field_create_fsm_order_prepare_values(self): "template_id": self.product_id.fsm_order_template_id.id, "todo": self.product_id.fsm_order_template_id.instructions, "category_ids": [(6, 0, categories.ids)], - "scheduled_duration": self.product_id.fsm_order_template_id.hours, + "scheduled_duration": self.product_id.fsm_order_template_id.duration, "sale_id": self.order_id.id, "sale_line_id": self.id, "company_id": self.company_id.id, @@ -139,7 +140,12 @@ def _field_service_generation(self): if rec.product_id.field_service_tracking == "line": rec._field_find_fsm_order() - def _prepare_invoice_line(self, qty): - res = super()._prepare_invoice_line(qty) - res.update({"fsm_order_id": self.fsm_order_id.id}) + 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/static/description/index.html b/fieldservice_sale/static/description/index.html index c71bfa5db3..b04fdf957f 100644 --- a/fieldservice_sale/static/description/index.html +++ b/fieldservice_sale/static/description/index.html @@ -1,15 +1,13 @@ - - - - Field Service - Sales - - - -
    -

    Field Service - Sales

    - - -

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

    -

    - 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/12.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. -

    -
    -
    -
    - +

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

    +

    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 index b37075e37e..e004260bd5 100644 --- a/fieldservice_sale/tests/__init__.py +++ b/fieldservice_sale/tests/__init__.py @@ -1,5 +1,5 @@ -# Copyright (C) 2019 Cl??ment Mombereau (Akretion) -# Copyright (C) 2020 Brian McMaster +# 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 ( diff --git a/fieldservice_sale/tests/test_fsm_sale_common.py b/fieldservice_sale/tests/test_fsm_sale_common.py index cf182afdd4..0ab2d2b9fa 100644 --- a/fieldservice_sale/tests/test_fsm_sale_common.py +++ b/fieldservice_sale/tests/test_fsm_sale_common.py @@ -1,9 +1,10 @@ # Copyright (C) 2019 Brian McMaster # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.addons.sale.tests.test_sale_common import TestCommonSaleNoChart +from odoo.addons.sale.tests.common import TestSaleCommonBase -class TestFSMSale(TestCommonSaleNoChart): + +class TestFSMSale(TestSaleCommonBase): @classmethod def setUpClass(cls): super(TestFSMSale, cls).setUpClass() @@ -18,7 +19,7 @@ def setUpFSMTemplates(cls): { "name": "Test FSM Template #1", "instructions": "These are the instructions for Template #1", - "hours": 2.25, + "duration": 2.25, } ) # Template 2 @@ -26,7 +27,7 @@ def setUpFSMTemplates(cls): { "name": "Test FSM Template #2", "instructions": "Template #2 requires a lot of work", - "hours": 4.5, + "duration": 4.5, } ) # Template 3 @@ -34,7 +35,7 @@ def setUpFSMTemplates(cls): { "name": "Test FSM Template #3", "instructions": "Complete the steps outlined for Template #3", - "hours": 0.75, + "duration": 0.75, } ) # Template 4 @@ -42,7 +43,7 @@ def setUpFSMTemplates(cls): { "name": "Test FSM Template #4", "instructions": "These notes apply to Template #4", - "hours": 0.75, + "duration": 0.75, } ) diff --git a/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py b/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py index 9c66f21fa2..49d2814601 100644 --- a/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py +++ b/fieldservice_sale/tests/test_fsm_sale_onchange_partner.py @@ -1,4 +1,4 @@ -# Copyright (C) 2019 Cl??ment Mombereau (Akretion) +# 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 TransactionCase @@ -16,11 +16,17 @@ def setUp(self): super(FSMSale, self).setUp() # create a parent company self.commercial_partner = self.env["res.partner"].create( - {"name": "Company Commercial Partner", "is_company": True} + { + "name": "Company Commercial Partner", + "is_company": True, + } ) # create a child partner self.partner = self.env["res.partner"].create( - {"name": "Child Partner", "parent_id": self.commercial_partner.id} + { + "name": "Child Partner", + "parent_id": self.commercial_partner.id, + } ) # create a child partner shipping address self.shipping_partner = self.env["res.partner"].create( diff --git a/fieldservice_sale/tests/test_fsm_sale_order.py b/fieldservice_sale/tests/test_fsm_sale_order.py index f04dd0a29b..4195ee5707 100644 --- a/fieldservice_sale/tests/test_fsm_sale_order.py +++ b/fieldservice_sale/tests/test_fsm_sale_order.py @@ -1,5 +1,6 @@ # Copyright (C) 2019 Brian McMaster # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from odoo import fields from .test_fsm_sale_common import TestFSMSale @@ -13,7 +14,15 @@ def setUpClass(cls): # 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 @@ -173,7 +182,11 @@ def _fulfill_order(self, order): ).id, } ) - order.write({"employee_timesheet_ids": [(6, 0, timesheet.ids)]}) + order.write( + { + "employee_timesheet_ids": [(6, 0, timesheet.ids)], + } + ) return order def test_sale_order_1(self): @@ -202,7 +215,10 @@ def test_sale_order_1(self): if self._isp_account_installed(): fsm_order = self._fulfill_order(fsm_order) fsm_order.write( - {"date_end": fields.Datetime.today(), "resolution": "Work completed"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order.action_complete() @@ -244,7 +260,10 @@ def test_sale_order_2(self): if self._isp_account_installed(): fsm_order = self._fulfill_order(fsm_order) fsm_order.write( - {"date_end": fields.Datetime.today(), "resolution": "Work completed"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order.action_complete() # qty delivered should be updated @@ -297,7 +316,10 @@ def test_sale_order_3(self): 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"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order_1.action_complete() self.assertTrue( @@ -307,7 +329,10 @@ def test_sale_order_3(self): 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"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order_2.action_complete() self.assertTrue( @@ -319,7 +344,7 @@ def test_sale_order_3(self): invoices = self.sale_order_3._create_invoices() # 2 invoices created self.assertEqual( - len(invoices.ids), 2, "FSM Sale: Sale Order 3 should create 2 invoices" + len(invoices.ids), 1, "FSM Sale: Sale Order 3 should create 1 invoices" ) inv_fsm_orders = FSM_Order for inv in invoices: @@ -337,7 +362,7 @@ 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. - - Three Invoices should be created (One for each FSM Order). + - One Invoices should be created (One for each FSM Order). """ sol1 = self.sol_service_per_line_4 sol2 = self.sol_service_per_line_5 @@ -377,7 +402,10 @@ def test_sale_order_4(self): 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"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order_1.action_complete() self.assertTrue( @@ -387,7 +415,10 @@ def test_sale_order_4(self): 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"} + { + "date_end": fields.Datetime.today(), + "resolution": "Work completed", + } ) fsm_order_2.action_complete() self.assertTrue( @@ -397,7 +428,10 @@ def test_sale_order_4(self): 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"} + { + "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 @@ -406,13 +440,5 @@ def test_sale_order_4(self): invoices = self.sale_order_4._create_invoices() # 3 invoices created self.assertEqual( - len(invoices.ids), 3, "FSM Sale: Sale Order 4 should create 3 invoices" - ) - inv_fsm_orders = FSM_Order - for inv in invoices: - inv_fsm_orders |= inv.fsm_order_ids - self.assertEqual( - len(inv_fsm_orders.ids), - 3, - "FSM Sale: There should be 3 orders for 3 invoices", + len(invoices.ids), 1, "FSM Sale: Sale Order 4 should create 1 invoice" ) diff --git a/fieldservice_sale/views/fsm_location.xml b/fieldservice_sale/views/fsm_location.xml index c8afa77643..299767e5b9 100644 --- a/fieldservice_sale/views/fsm_location.xml +++ b/fieldservice_sale/views/fsm_location.xml @@ -1,4 +1,5 @@ + fsm.location.form @@ -9,7 +10,6 @@ - diff --git a/fieldservice_sale/views/fsm_order.xml b/fieldservice_sale/views/fsm_order.xml index d19e4da8f1..92f9373b03 100644 --- a/fieldservice_sale/views/fsm_order.xml +++ b/fieldservice_sale/views/fsm_order.xml @@ -1,4 +1,5 @@ + fsm.order @@ -18,4 +19,5 @@ + diff --git a/fieldservice_sale/views/res_branch.xml b/fieldservice_sale/views/res_branch.xml deleted file mode 100644 index 9629a57a15..0000000000 --- a/fieldservice_sale/views/res_branch.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - res.branch.form.pricelist - res.branch - - - - - - - - diff --git a/fieldservice_sale/views/res_config_settings.xml b/fieldservice_sale/views/res_config_settings.xml index 7d57014d73..197f470666 100644 --- a/fieldservice_sale/views/res_config_settings.xml +++ b/fieldservice_sale/views/res_config_settings.xml @@ -1,8 +1,11 @@ + + - + + From a42b3c6c8c815e435697104ffff47aaad6b5ab1d Mon Sep 17 00:00:00 2001 From: hparfr Date: Tue, 20 Jul 2021 16:49:19 +0200 Subject: [PATCH 53/77] fieldservice_sale: remove required tpl in prd view Create a blank fsm from a SO is a valid use case. And it make more sense when used with fsm_recurring_sale Implement rfc #735 --- fieldservice_sale/views/product_template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fieldservice_sale/views/product_template.xml b/fieldservice_sale/views/product_template.xml index a1da19f361..a03626e2bd 100644 --- a/fieldservice_sale/views/product_template.xml +++ b/fieldservice_sale/views/product_template.xml @@ -8,7 +8,7 @@ From de9c11b681930263e0a41041c4bda7ce0cde45d1 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Wed, 28 Jul 2021 20:30:13 +0200 Subject: [PATCH 54/77] [FIX] fieldservice_sale: Restrict views to authorized users Not putting groups on the view makes the rest of the users that access to these views to receive a permission error. It's also not enough to put the groups on the field, but the view. --- fieldservice_sale/__manifest__.py | 2 +- fieldservice_sale/views/fsm_order.xml | 1 + fieldservice_sale/views/product_template.xml | 1 + fieldservice_sale/views/sale_order.xml | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fieldservice_sale/__manifest__.py b/fieldservice_sale/__manifest__.py index aeade35e98..b2f41d9344 100644 --- a/fieldservice_sale/__manifest__.py +++ b/fieldservice_sale/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Field Service - Sales", - "version": "14.0.1.0.0", + "version": "14.0.1.2.0", "summary": "Sell field services.", "category": "Field Service", "author": "Open Source Integrators, Odoo Community Association (OCA)", diff --git a/fieldservice_sale/views/fsm_order.xml b/fieldservice_sale/views/fsm_order.xml index 92f9373b03..47a942350a 100644 --- a/fieldservice_sale/views/fsm_order.xml +++ b/fieldservice_sale/views/fsm_order.xml @@ -3,6 +3,7 @@ fsm.order +