diff --git a/fieldservice_mobile/README.rst b/fieldservice_mobile/README.rst new file mode 100644 index 0000000000..2c526f55be --- /dev/null +++ b/fieldservice_mobile/README.rst @@ -0,0 +1,38 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +==================== +Field Service Mobile +==================== + +This module is manage FSM mobile stages based on configuration. + +Configuration +============= + +To configure this module, you need to: + +* Go to Field Service > Configuration > Stages. +* Check Display in Mobile for display stage in FSM Mobile. +* Check Display in Odoo for display stage in Odoo FSM Order. +* Select a server action based on Stages. + +* Manage domain on Automated Actions based on Stage sequence. + +For Example:- If the Started stage sequence is 6. + +* Go to Settings > Automated Actions > FSM Order Started Stage Update > Apply on > [["stage_id.sequence","=",6]] + +Credits +======= + +* Open Source Integrators +* Serpent Consulting Services Pvt. Ltd. + +Contributors +~~~~~~~~~~~~ + +* Wolfgang Hall +* Sandip Mangukiya +* Serpent Consulting Services Pvt. Ltd. diff --git a/fieldservice_mobile/__init__.py b/fieldservice_mobile/__init__.py new file mode 100644 index 0000000000..69f7babdfb --- /dev/null +++ b/fieldservice_mobile/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/fieldservice_mobile/__manifest__.py b/fieldservice_mobile/__manifest__.py new file mode 100644 index 0000000000..e77973b222 --- /dev/null +++ b/fieldservice_mobile/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Field Service Mobile", + "summary": "Field Service Mobile backend support.", + "license": "AGPL-3", + "version": "12.0.1.1.0", + "category": "Field Service", + "author": "Open Source Integrators", + "website": "https://github.com/ursais/osi-addons", + "depends": ["fieldservice_stage_server_action", "stock"], + "data": [ + "security/ir_rule.xml", + "security/ir.model.access.csv", + "data/base_automation.xml", + "views/res_config_settings.xml", + "views/fsm_stage_view.xml", + "views/fsm_order_view.xml", + ], + "development_status": "Beta", + "maintainers": ["wolfhall"], +} diff --git a/fieldservice_mobile/data/base_automation.xml b/fieldservice_mobile/data/base_automation.xml new file mode 100644 index 0000000000..e181dc8754 --- /dev/null +++ b/fieldservice_mobile/data/base_automation.xml @@ -0,0 +1,89 @@ + + + + FSM Order Started Stage Update + + on_write + + [["stage_id.sequence","=",6]] + code + for rec in records: + stage_rec = env['fsm.stage.history'].search([('order_id', '=', rec.id)], order='id desc', limit=1) + call_it = False + if not stage_rec: + call_it = True + if stage_rec.stage_id != rec.stage_id: + call_it = True + if call_it and rec.stage_id.action_id: + rec.write( + {'date_start': datetime.datetime.now(), + 'fsm_stage_history_ids': [(0, 0, {'start_datetime': datetime.datetime.now(), 'stage_id': rec.stage_id.id, 'duration': 0.0, 'total_duration': 0.0 + })]}) + + + + FSM Order Break Stage Update + + on_write + + [["stage_id.sequence","=",7]] + code + for rec in records: + stage_rec = env['fsm.stage.history'].search([('order_id', '=', rec.id)], order='id desc', limit=1) + call_it = False + if not stage_rec: + call_it = True + if stage_rec.stage_id != rec.stage_id: + call_it = True + if call_it and rec.stage_id.action_id: + delta = datetime.datetime.now() - stage_rec.start_datetime + duration = round((delta.total_seconds() / 3600), 2) + rec.write( + {'fsm_stage_history_ids': [(0, 0, {'start_datetime': datetime.datetime.now(), 'stage_id': rec.stage_id.id, 'duration': duration, 'total_duration': round((duration + stage_rec.total_duration), 2) + })]}) + + + + FSM Order Resume Stage Update + + on_write + + [["stage_id.sequence","=", 8]] + code + for rec in records: + stage_rec = env['fsm.stage.history'].search([('order_id', '=', rec.id)], order='id desc', limit=1) + call_it = False + if not stage_rec: + call_it = True + if stage_rec.stage_id != rec.stage_id: + call_it = True + if call_it and rec.stage_id.action_id: + rec.write( + {'fsm_stage_history_ids': [(0, 0, {'start_datetime': datetime.datetime.now(), 'stage_id': rec.stage_id.id, 'duration': 0.0, 'total_duration': round((rec.duration + stage_rec.total_duration), 2) + })]}) + + + + FSM Order Completed Stage Update + + on_write + + [["stage_id.sequence","=",9]] + code + for rec in records: + stage_rec = env['fsm.stage.history'].search([('order_id', '=', rec.id)], order='id desc', limit=1) + call_it = False + if not stage_rec: + call_it = True + if stage_rec.stage_id != rec.stage_id: + call_it = True + if call_it and rec.stage_id.action_id: + delta = datetime.datetime.now() - stage_rec.start_datetime + duration = round((delta.total_seconds() / 3600), 2) + rec.write( + {'date_end': datetime.datetime.now(), + 'fsm_stage_history_ids': [(0, 0, {'start_datetime': datetime.datetime.now(), 'stage_id': rec.stage_id.id, 'duration': duration, 'total_duration': round((duration + stage_rec.total_duration), 2) + })]}) + + + diff --git a/fieldservice_mobile/models/__init__.py b/fieldservice_mobile/models/__init__.py new file mode 100644 index 0000000000..c013f49c85 --- /dev/null +++ b/fieldservice_mobile/models/__init__.py @@ -0,0 +1,7 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import fsm_stage +from . import fsm_order +from . import fsm_stage_history +from . import res_config_settings +from . import res_users diff --git a/fieldservice_mobile/models/fsm_order.py b/fieldservice_mobile/models/fsm_order.py new file mode 100644 index 0000000000..d95c34f874 --- /dev/null +++ b/fieldservice_mobile/models/fsm_order.py @@ -0,0 +1,43 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class FSMOrder(models.Model): + _inherit = "fsm.order" + + @api.depends("date_start", "date_end") + def _compute_duration(self): + res = super()._compute_duration() + for rec in self: + if rec.fsm_stage_history_ids and rec.date_end: + stage_rec = self.env["fsm.stage.history"].search( + [("order_id", "=", rec.id)], order="id desc", limit=1 + ) + rec.duration = stage_rec.total_duration + elif not rec.date_end: + rec.duration = 0.0 + return res + + duration = fields.Float( + string="Actual duration", + compute=_compute_duration, + help="Actual duration in hours", + store=True, + ) + fsm_stage_history_ids = fields.One2many( + "fsm.stage.history", "order_id", string="Stage History" + ) + + @api.model + def create_fsm_attachment(self, name, datas, res_model, res_id): + if res_model == "fsm.order": + attachment = self.env["ir.attachment"].sudo().create({ + "name": name, + "datas": datas, + "res_model": res_model, + "res_id": res_id, + }) + return attachment.id diff --git a/fieldservice_mobile/models/fsm_stage.py b/fieldservice_mobile/models/fsm_stage.py new file mode 100644 index 0000000000..a141796661 --- /dev/null +++ b/fieldservice_mobile/models/fsm_stage.py @@ -0,0 +1,12 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class FSMStage(models.Model): + _inherit = "fsm.stage" + + is_display_in_mobile = fields.Boolean("Display in Mobile", default=False) + is_display_in_odoo = fields.Boolean("Display in Odoo", default=True) diff --git a/fieldservice_mobile/models/fsm_stage_history.py b/fieldservice_mobile/models/fsm_stage_history.py new file mode 100644 index 0000000000..0af6d977d3 --- /dev/null +++ b/fieldservice_mobile/models/fsm_stage_history.py @@ -0,0 +1,16 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class FsmStageHistory(models.Model): + _name = "fsm.stage.history" + _description = "FSM Stage History" + + order_id = fields.Many2one("fsm.order", string="FSM Order") + start_datetime = fields.Datetime("Start Date&time") + stage_id = fields.Many2one("fsm.stage", string="Stage") + duration = fields.Float(string="Duration",) + total_duration = fields.Float(string="Total Duration",) diff --git a/fieldservice_mobile/models/res_config_settings.py b/fieldservice_mobile/models/res_config_settings.py new file mode 100644 index 0000000000..6a4ccad3f2 --- /dev/null +++ b/fieldservice_mobile/models/res_config_settings.py @@ -0,0 +1,18 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + fsm_allow_portal_view_move_qty = fields.Boolean( + string="Allow portal user to view stock move quantities", + config_parameter="fieldservice_mobile.fsm_allow_portal_view_move_qty", + ) + fsm_allow_portal_update_move_qty = fields.Boolean( + string="Allow portal user update of stock move quantities", + config_parameter="fieldservice_mobile.fsm_allow_portal_update_move_qty", + ) diff --git a/fieldservice_mobile/models/res_users.py b/fieldservice_mobile/models/res_users.py new file mode 100644 index 0000000000..1ed40e86d9 --- /dev/null +++ b/fieldservice_mobile/models/res_users.py @@ -0,0 +1,26 @@ +# Copyright (C) 2020 Open Source Integrators +# Copyright (C) 2020 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class Users(models.Model): + _inherit = "res.users" + + @api.model + def get_portal_config_values(self, config_parameters=[]): + params_dict = {} + for config_param in config_parameters: + if config_param in [ + "fieldservice_mobile.fsm_allow_portal_view_move_qty", + "fieldservice_mobile.fsm_allow_portal_update_move_qty", + "fieldservice_mobile.fsm_allow_portal_validate_move_qty", + "fieldservice_sale_order_line.fsm_allow_portal_view_sol_qty", + "fieldservice_sale_order_line.fsm_allow_portal_update_sol_qty", + ]: + params = self.env["ir.config_parameter"].sudo() + params_dict.update({ + config_param: bool(params.get_param(config_param)) + }) + return params_dict diff --git a/fieldservice_mobile/security/ir.model.access.csv b/fieldservice_mobile/security/ir.model.access.csv new file mode 100644 index 0000000000..32a0535eca --- /dev/null +++ b/fieldservice_mobile/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_fsm_stage_history_fsm_user,fsm.stage.history.user,model_fsm_stage_history,fieldservice.group_fsm_user,1,1,1,0 +access_fsm_stage_history_fsm_manager,fsm.stage.history.manager,model_fsm_stage_history,fieldservice.group_fsm_manager,1,1,1,1 +access_fsm_stage_history_portal,fsm.stage.history.portal,model_fsm_stage_history,base.group_portal,1,1,1,0 +stock.access_stock_move_line_portal,stock.move.line portal,stock.model_stock_move_line,base.group_portal,1,0,1,0 \ No newline at end of file diff --git a/fieldservice_mobile/security/ir_rule.xml b/fieldservice_mobile/security/ir_rule.xml new file mode 100644 index 0000000000..173e26c560 --- /dev/null +++ b/fieldservice_mobile/security/ir_rule.xml @@ -0,0 +1,14 @@ + + + + Portal Partner multi-company + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + + + + diff --git a/fieldservice_mobile/static/description/icon.png b/fieldservice_mobile/static/description/icon.png new file mode 100644 index 0000000000..955674d8f0 Binary files /dev/null and b/fieldservice_mobile/static/description/icon.png differ diff --git a/fieldservice_mobile/views/fsm_order_view.xml b/fieldservice_mobile/views/fsm_order_view.xml new file mode 100644 index 0000000000..e816ee8436 --- /dev/null +++ b/fieldservice_mobile/views/fsm_order_view.xml @@ -0,0 +1,31 @@ + + + + view.fsm.order.inherit.mobile + fsm.order + + + + [('stage_type', '=', 'order'), + ('team_ids', 'in', (team_id, False)), + ('is_display_in_odoo', '=', True)] + + + float_time + + + + + + + + + + + + + + + + + diff --git a/fieldservice_mobile/views/fsm_stage_view.xml b/fieldservice_mobile/views/fsm_stage_view.xml new file mode 100644 index 0000000000..a8ac48f942 --- /dev/null +++ b/fieldservice_mobile/views/fsm_stage_view.xml @@ -0,0 +1,15 @@ + + + + fsm.stage.form.inherit.mobile + fsm.stage + + + + + + + + + + diff --git a/fieldservice_mobile/views/res_config_settings.xml b/fieldservice_mobile/views/res_config_settings.xml new file mode 100644 index 0000000000..b6046ad9da --- /dev/null +++ b/fieldservice_mobile/views/res_config_settings.xml @@ -0,0 +1,38 @@ + + + + res.config.settings.view.form.fsm.mobile + res.config.settings + + + +
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
\ No newline at end of file