diff --git a/fieldservice_mobile/README.rst b/fieldservice_mobile/README.rst new file mode 100644 index 0000000000..b7f0c7ad99 --- /dev/null +++ b/fieldservice_mobile/README.rst @@ -0,0 +1,48 @@ +.. 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]] + +Features on the mobile application will be visible depending on the groups set on this model. + +Usage +============= +1) Navigate to the "Field Service" application +2) Under menu item "Configuration", select "FSM Mobile Features" +3) Select Installed Modules for FSM Mobile Dynamic Menu and it's records +4) Select a feature and add/remove groups + +Credits +======= + +* Open Source Integrators +* Serpent Consulting Services Pvt. Ltd. + +Contributors +~~~~~~~~~~~~ + +* Wolfgang Hall +* Sandip Mangukiya +* Serpent Consulting Services Pvt. Ltd. +* Ammar Officewala 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..f9247483fa --- /dev/null +++ b/fieldservice_mobile/__manifest__.py @@ -0,0 +1,38 @@ +# 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": "18.0.1.0.0", + "category": "Field Service", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/field-service", + "depends": [ + "fieldservice_stage_server_action", + "stock", + "analytic", + "maintenance", + "fieldservice_vehicle", + "fieldservice_sale", + "calendar", + ], + "data": [ + "security/ir_rule.xml", + "security/ir.model.access.csv", + "security/fieldservice_mobile_security.xml", + "data/server_actions.xml", + "data/base_automation.xml", + "data/feature_line.xml", + "data/feature_mapping.xml", + "views/res_config_settings.xml", + "views/fsm_stage_view.xml", + "views/fsm_order_view.xml", + "views/mobile_feature_mapping.xml", + "views/mobile_feature_line.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..fadc60d6c9 --- /dev/null +++ b/fieldservice_mobile/data/base_automation.xml @@ -0,0 +1,49 @@ + + + FSM Order Started Stage Update + + on_write + + [["stage_id.sequence", "=", 6]] + + + + + FSM Order Break Stage Update + + on_write + + [["stage_id.sequence", "=", 7]] + + + + + FSM Order Resume Stage Update + + on_write + + [["stage_id.sequence", "=", 8]] + + + + + FSM Order Completed Stage Update + + on_write + + [["stage_id.sequence", "=", 9]] + + + diff --git a/fieldservice_mobile/data/feature_line.xml b/fieldservice_mobile/data/feature_line.xml new file mode 100644 index 0000000000..68285347b5 --- /dev/null +++ b/fieldservice_mobile/data/feature_line.xml @@ -0,0 +1,107 @@ + + + + Location + LOC + + + + Contact + CON + + + + Notes + NOT + + + + Chatter + CHA + + + + Documents + DOC + + + + Pictures + PIC + + + + Timesheets + TIM + + + + Signature + SIG + + + + Equipment + EQU + + + + Pickup/Delivery + DEL + + + + Sale Order Lines + SOL + + + + Durations + DUR + + + + Stock Requests + STO + + + diff --git a/fieldservice_mobile/data/feature_mapping.xml b/fieldservice_mobile/data/feature_mapping.xml new file mode 100644 index 0000000000..08f5a9fd57 --- /dev/null +++ b/fieldservice_mobile/data/feature_mapping.xml @@ -0,0 +1,28 @@ + + + + Default FSM Mobile Feature Mapping + + + + diff --git a/fieldservice_mobile/data/server_actions.xml b/fieldservice_mobile/data/server_actions.xml new file mode 100644 index 0000000000..196f81caf5 --- /dev/null +++ b/fieldservice_mobile/data/server_actions.xml @@ -0,0 +1,103 @@ + + + FSM Order Started Stage Update Action + + 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 Action + + 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 Action + + 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 Action + + 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..2d76926f19 --- /dev/null +++ b/fieldservice_mobile/models/__init__.py @@ -0,0 +1,10 @@ +# 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 +from . import ir_attachment +from . import fsm_mobile_feature_mapping +from . import fsm_mobile_feature_line diff --git a/fieldservice_mobile/models/fsm_mobile_feature_line.py b/fieldservice_mobile/models/fsm_mobile_feature_line.py new file mode 100644 index 0000000000..5a22db062c --- /dev/null +++ b/fieldservice_mobile/models/fsm_mobile_feature_line.py @@ -0,0 +1,15 @@ +# Copyright (C) 2022 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class FSMMobileFeatureLine(models.Model): + _name = "fsm.mobile.feature.line" + _description = "FSM Mobile Feature Line" + + feature_id = fields.Many2one("fsm.mobile.feature.mapping", string="Feature Mapping") + name = fields.Char(string="Feature Name") + group_ids = fields.Many2many("res.groups", string="Groups") + code = fields.Char() diff --git a/fieldservice_mobile/models/fsm_mobile_feature_mapping.py b/fieldservice_mobile/models/fsm_mobile_feature_mapping.py new file mode 100644 index 0000000000..2e9742231c --- /dev/null +++ b/fieldservice_mobile/models/fsm_mobile_feature_mapping.py @@ -0,0 +1,96 @@ +# Copyright (C) 2022 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class FSMMobileFeatureMapping(models.Model): + _name = "fsm.mobile.feature.mapping" + _description = "FSM Mobile Feature Mapping" + + name = fields.Char(string="Mapping Name") + installed_module_ids = fields.Many2many( + "ir.module.module", + string="Installed Modules", + domain=[("state", "=", "installed")], + ) + feature_line_ids = fields.One2many( + "fsm.mobile.feature.line", "feature_id", string="Mobile Feature Lines" + ) + company_id = fields.Many2one( + "res.company", + string="Company", + default=lambda self: self.env.user.company_id.id, + ) + state = fields.Selection( + [("draft", "Draft"), ("active", "Active")], + default="draft", + ) + + @api.depends("name") + def _compute_display_name(self): + for record in self: + record.display_name = record.name + + def set_to_draft(self): + """Set to draft state.""" + for rec in self: + rec.state = "draft" + + def set_to_active(self): + """Set to active state.""" + record = self.search([("state", "=", "active")]) + if record: + raise UserError( + _("Active record is already exits in FSM Mobile Feature Mapping!") + ) + for rec in self: + rec.state = "active" + + def unlink(self): + """Override unlink method for can't delete active FSM Mobile Feature Mapping.""" + for rec in self: + if rec.state == "active": + raise UserError( + _( + "You can't delete FSM Mobile Feature Mapping which is in" + " an active state!" + ) + ) + return super().unlink() + + @api.model + def get_fsm_mobile_feature_mapping_values(self, user_id): + fsm_feature_mapping_obj = self.env["fsm.mobile.feature.mapping"] + fsm_feature_mapping_rec = fsm_feature_mapping_obj.search( + [("state", "=", "active")], limit=1 + ) + params_dict = {} + feature_mapping_list = [] + installed_modules_list = [] + for f_line_rec in fsm_feature_mapping_rec.feature_line_ids: + group_ids = f_line_rec.group_ids.sudo().filtered( + lambda line: user_id in line.users.ids + ) + if group_ids: + feature_mapping_list.append( + { + "id": f_line_rec.id, + "name": f_line_rec.name, + "group_ids": group_ids.ids, + "code": f_line_rec.code, + } + ) + for inst_module in fsm_feature_mapping_rec.sudo().installed_module_ids: + installed_modules_list.append( + {"id": inst_module.id, "name": inst_module.name} + ) + if feature_mapping_list and installed_modules_list: + params_dict.update( + { + "feature_mapping": feature_mapping_list, + "installed_modules": installed_modules_list, + } + ) + return params_dict diff --git a/fieldservice_mobile/models/fsm_order.py b/fieldservice_mobile/models/fsm_order.py new file mode 100644 index 0000000000..a7ff81bc39 --- /dev/null +++ b/fieldservice_mobile/models/fsm_order.py @@ -0,0 +1,98 @@ +# 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 + + @api.depends("sale_id.transaction_ids.state") + def _compute_payment_state(self): + for rec in self: + payment_state = "not_paid" + paid_payment_check_list = [ + True if paym.state == "done" else False + for paym in rec.sale_id.transaction_ids + ] + if rec.sale_id.transaction_ids: + if all(paid_payment_check_list): + payment_state = "paid" + elif rec.sale_id.transaction_ids.filtered( + lambda r: r.state == "pending" + ): + payment_state = "pending" + rec.payment_state = payment_state + + 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" + ) + payment_state = fields.Selection( + [("not_paid", "Not Paid"), ("paid", "Paid"), ("pending", "Pending")], + compute="_compute_payment_state", + store=True, + ) + + @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 + + @api.model + def generate_so_payment_link(self, fsm_order_id): + order = self.env["fsm.order"].browse(fsm_order_id) + if not order.sale_id: + return { + "payment_status": False, + "message": "The sale order is not found related to this FSO.", + } + payment_link_id = ( + self.env["payment.link.wizard"] + .with_context( + default_res_model="sale.order", default_res_id=order.sale_id.id + ) + .sudo() + .create( + { + "res_model": "sale.order", + "res_id": order.sale_id.id, + "amount": order.sale_id.amount_total, + "currency_id": order.sale_id.currency_id.id, + "partner_id": order.sale_id.partner_id.id, + "description": order.sale_id.name, + } + ) + ) + return {"payment_status": True, "payment_link": payment_link_id.link} 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..0bc8d1e881 --- /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") + duration = fields.Float() + total_duration = fields.Float() diff --git a/fieldservice_mobile/models/ir_attachment.py b/fieldservice_mobile/models/ir_attachment.py new file mode 100644 index 0000000000..f5d96f1e6f --- /dev/null +++ b/fieldservice_mobile/models/ir_attachment.py @@ -0,0 +1,80 @@ +# Copyright (C) 2021 Open Source Integrators +# Copyright (C) 2021 Serpent Consulting Services Pvt. Ltd. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from collections import defaultdict + +from odoo import _, api, models +from odoo.exceptions import AccessError + + +class IrAttachment(models.Model): + _inherit = "ir.attachment" + + """Overwrite check method for allow portal user to read attachment""" + + @api.model + def check(self, mode, values=None): + """Restricts the access to an ir.attachment, according to referred mode""" + if self.env.is_superuser(): + return True + # Always require an internal user (aka, employee) to access to a attachment + + # if not (self.env.is_admin() or + # self.env.user.has_group('base.group_user')): + # raise AccessError(_("Sorry, you are not + # allowed to access this document.")) + + # collect the records to check (by model) + model_ids = defaultdict(set) # {model_name: set(ids)} + if self: + # DLE P173: `test_01_portal_attachment` + self.env["ir.attachment"].flush_model( + ["res_model", "res_id", "public", "res_field"] + ) + self._cr.execute( + """SELECT res_model, res_id, create_uid, public, res_field + FROM ir_attachment WHERE id IN %s""", + [tuple(self.ids)], + ) + for ( + res_model, + res_id, + _create_uid, + public, + res_field, + ) in self._cr.fetchall(): + if not self.env.is_system() and res_field: + raise AccessError( + _("Sorry, you are not allowed to access this document.") + ) + if public and mode == "read": + continue + if not (res_model and res_id): + continue + model_ids[res_model].add(res_id) + if values and values.get("res_model") and values.get("res_id"): + model_ids[values["res_model"]].add(values["res_id"]) + + # check access rights on the records + for res_model, res_ids in model_ids.items(): + # ignore attachments that are not attached to a resource anymore + # when checking access rights (resource was deleted but attachment + # was not) + if res_model not in self.env: + continue + if ( + res_model == "res.users" + and len(res_ids) == 1 + and self.env.uid == list(res_ids)[0] + ): + # by default a user cannot write on itself, + # despite the list of writeable fields + # e.g. in the case of a user inserting an image into his image signature + # we need to bypass this check which would needlessly throw us away + continue + records = self.env[res_model].browse(res_ids).exists() + # For related models, check if we can write to the model, as unlinking + # and creating attachments can be seen as an update to the model + access_mode = "write" if mode in ("create", "unlink") else mode + records.check_access_rights(access_mode) + records.check_access_rule(access_mode) 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..b21eba1285 --- /dev/null +++ b/fieldservice_mobile/models/res_users.py @@ -0,0 +1,27 @@ +# 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=False): + if not config_parameters: + config_parameters = [] + params_dict = {} + group_params = [ + "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", + ] + for config_param in config_parameters: + if config_param in group_params: + 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/pyproject.toml b/fieldservice_mobile/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/fieldservice_mobile/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/fieldservice_mobile/security/fieldservice_mobile_security.xml b/fieldservice_mobile/security/fieldservice_mobile_security.xml new file mode 100644 index 0000000000..4605c52a30 --- /dev/null +++ b/fieldservice_mobile/security/fieldservice_mobile_security.xml @@ -0,0 +1,7 @@ + + + User can only see own feature mapping + + [('company_id.id','=',user.company_id.id)] + + diff --git a/fieldservice_mobile/security/ir.model.access.csv b/fieldservice_mobile/security/ir.model.access.csv new file mode 100644 index 0000000000..d4838088d5 --- /dev/null +++ b/fieldservice_mobile/security/ir.model.access.csv @@ -0,0 +1,35 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_res_territory_portal,access.res.territory.portal,base_territory.model_res_territory,base.group_portal,1,0,0,0 +access_res_branch_portal,access.res.branch.portal,base_territory.model_res_branch,base.group_portal,1,0,0,0 +access_res_district_portal,access.res.district.portal,base_territory.model_res_district,base.group_portal,1,0,0,0 +access_res_region_portal,access.res.region.portal,base_territory.model_res_region,base.group_portal,1,0,0,0 +access_fsm_stage_portal,access.fsm.stage.portal,fieldservice.model_fsm_stage,base.group_portal,1,0,0,0 +access_fsm_tag_portal,access.fsm.tag.portal,fieldservice.model_fsm_tag,base.group_portal,1,0,0,0 +access_fsm_person_portal,access.fsm.person.portal,fieldservice.model_fsm_person,base.group_portal,1,1,0,0 +access_fsm_location_portal,access.fsm.location.portal,fieldservice.model_fsm_location,base.group_portal,1,0,0,0 +access_fsm_order_portal,access.fsm.order.portal,fieldservice.model_fsm_order,base.group_portal,1,1,0,0 +access_fsm_equipment_portal,access.fsm.equipment.portal,fieldservice.model_fsm_equipment,base.group_portal,1,0,0,0 +access_fsm_category_portal,access.fsm.category.portal,fieldservice.model_fsm_category,base.group_portal,1,0,0,0 +access_fsm_template_portal,access.fsm.template.portal,fieldservice.model_fsm_template,base.group_portal,1,0,0,0 +access_fsm_team_portal,access.fsm.team.portal,fieldservice.model_fsm_team,base.group_portal,1,0,0,0 +access_fsm_location_person_portal,access.fsm.location.person.portal,fieldservice.model_fsm_location_person,base.group_portal,1,0,0,0 +access_fsm_order_type_portal,access.fsm.order.type.portal,fieldservice.model_fsm_order_type,base.group_portal,1,0,0,0 +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,0,0 +access_stock_location_portal,access.stock.location.portal,stock.model_stock_location,base.group_portal,1,0,0,0 +access_stock_warehouse_portal,access.stock.warehouse.portal,stock.model_stock_warehouse,base.group_portal,1,0,0,0 +access_account_analytic_line_portal,access.account.analytic.line.portal,analytic.model_account_analytic_line,base.group_portal,1,0,0,0 +access_stock_picking_type_portal,access.stock.picking.type.portal,stock.model_stock_picking_type,base.group_portal,1,0,0,0 +access_fsm_vehicle_portal,access.fsm.vehicle.portal,fieldservice_vehicle.model_fsm_vehicle,base.group_portal,1,0,0,0 +access_maintenance_equipment_portal,access.maintenance.equipment.portal,maintenance.model_maintenance_equipment,base.group_portal,1,0,0,0 +access_ir_attachment_portal,access.ir.attachment.portal,base.model_ir_attachment,base.group_portal,1,0,0,0 +access_mobile_feature_mapping_user,mobile.feature.user,fieldservice_mobile.model_fsm_mobile_feature_mapping,base.group_user,1,0,0,0 +access_mobile_feature_mapping_manager,mobile.feature.manager,fieldservice_mobile.model_fsm_mobile_feature_mapping,fieldservice.group_fsm_manager,1,1,1,1 +access_mobile_feature_line_user,mobile.feature.line.user,fieldservice_mobile.model_fsm_mobile_feature_line,base.group_user,1,0,0,0 +access_mobile_feature_line_manager,mobile.feature.line.manager,fieldservice_mobile.model_fsm_mobile_feature_line,fieldservice.group_fsm_manager,1,1,1,1 +access_mobile_feature_line_portal,mobile.feature.line.portal,fieldservice_mobile.model_fsm_mobile_feature_line,base.group_portal,1,0,0,0 +access_mobile_feature_mapping_user_portal,mobile.feature.user.portal,fieldservice_mobile.model_fsm_mobile_feature_mapping,base.group_portal,1,0,0,0 +access_mobile_feature_mapping_manager_portal,mobile.feature.manager.portal,fieldservice_mobile.model_fsm_mobile_feature_mapping,base.group_portal,1,0,0,0 +access_calendar_recurrence_portal,access_calendar_recurrence_portal,calendar.model_calendar_recurrence,base.group_portal,1,0,0,0 diff --git a/fieldservice_mobile/security/ir_rule.xml b/fieldservice_mobile/security/ir_rule.xml new file mode 100644 index 0000000000..5c21251633 --- /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..e3757caa15 Binary files /dev/null and b/fieldservice_mobile/static/description/icon.png differ diff --git a/fieldservice_mobile/static/description/icon.svg b/fieldservice_mobile/static/description/icon.svg new file mode 100644 index 0000000000..c27c090fda --- /dev/null +++ b/fieldservice_mobile/static/description/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fieldservice_mobile/views/fsm_order_view.xml b/fieldservice_mobile/views/fsm_order_view.xml new file mode 100644 index 0000000000..92354188dc --- /dev/null +++ b/fieldservice_mobile/views/fsm_order_view.xml @@ -0,0 +1,35 @@ + + + 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..6c750aaf28 --- /dev/null +++ b/fieldservice_mobile/views/fsm_stage_view.xml @@ -0,0 +1,13 @@ + + + fsm.stage.form.inherit.mobile + fsm.stage + + + + + + + + + diff --git a/fieldservice_mobile/views/mobile_feature_line.xml b/fieldservice_mobile/views/mobile_feature_line.xml new file mode 100644 index 0000000000..b1584ce956 --- /dev/null +++ b/fieldservice_mobile/views/mobile_feature_line.xml @@ -0,0 +1,17 @@ + + + + fsm.mobile.feature.line.view + fsm.mobile.feature.line + +
+ + +
+
+
+
diff --git a/fieldservice_mobile/views/mobile_feature_mapping.xml b/fieldservice_mobile/views/mobile_feature_mapping.xml new file mode 100644 index 0000000000..3b0a258b38 --- /dev/null +++ b/fieldservice_mobile/views/mobile_feature_mapping.xml @@ -0,0 +1,80 @@ + + + + fsm.mobile.feature.mapping.list.view + fsm.mobile.feature.mapping + + + + + + + + + + fsm.mobile.feature.mapping.view + fsm.mobile.feature.mapping + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + + Field Service Mobile Feature Mapping + fsm.mobile.feature.mapping + + list,form + + + + +
diff --git a/fieldservice_mobile/views/res_config_settings.xml b/fieldservice_mobile/views/res_config_settings.xml new file mode 100644 index 0000000000..8706908819 --- /dev/null +++ b/fieldservice_mobile/views/res_config_settings.xml @@ -0,0 +1,33 @@ + + + res.config.settings.view.form.fsm.mobile + res.config.settings + + + + + + + + + + + + + + +