From 5469dd82c4af3ab575eddd27d02536d5d2107ffe Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Thu, 15 Jun 2023 13:16:37 -0400 Subject: [PATCH] bemade_fsm: Improvements to the UI and data model for site contacts and equipment. Re: #11. --- __manifest__.py | 2 +- models/equipment.py | 85 +++++++------------- models/res_partner.py | 62 +++++++++------ security/ir.model.access.csv | 3 +- static/tests/tours/task_equipment_tour.js | 14 ++++ tests/__init__.py | 2 + tests/test_bemade_fsm_common.py | 42 ++++++++++ tests/test_equipment.py | 32 ++++++++ tests/test_task_template.py | 28 +------ views/equipment.xml | 1 - views/equipment_location.xml | 96 ----------------------- views/menus.xml | 32 ++++++++ views/res_partner.xml | 56 ++++++++++--- views/task_views.xml | 16 ++++ 14 files changed, 254 insertions(+), 217 deletions(-) create mode 100644 static/tests/tours/task_equipment_tour.js create mode 100644 tests/test_bemade_fsm_common.py create mode 100644 tests/test_equipment.py delete mode 100644 views/equipment_location.xml create mode 100644 views/menus.xml create mode 100644 views/task_views.xml diff --git a/__manifest__.py b/__manifest__.py index d4715c4..3c9b327 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -37,11 +37,11 @@ ], 'data': ['views/task_template_views.xml', 'views/equipment.xml', - 'views/equipment_location.xml', 'security/ir.model.access.csv', 'views/product_views.xml', 'views/res_partner.xml', 'views/menus.xml', + 'views/task_views.xml', ], 'assets': { 'web.assets_tests': [ diff --git a/models/equipment.py b/models/equipment.py index c928988..203037e 100644 --- a/models/equipment.py +++ b/models/equipment.py @@ -2,7 +2,6 @@ from odoo import api, fields, models class EquipmentTag(models.Model): - _name = "bemade_fsm.equipment.tag" _description = 'Field service equipment category' @@ -21,36 +20,6 @@ class EquipmentType(models.Model): name = fields.Char(string='Intervention Name', required=True, translate=True) - -class EquipmentLocation(models.Model): - _name = 'bemade_fsm.equipment.location' - _description = 'Field service location for equipment' - _inherit = ['mail.thread', 'mail.activity.mixin'] - - name = fields.Char(string='Name', required=True, translate=True) - - more_info = fields.Char(string='MOre info') - - partner_id = fields.Many2one(comodel_name='res.partner', - string="Address", - tracking=True, - domain="[('is_site', '=', True)]", - required=True) - - equipment_count = fields.Integer(compute='_compute_equipment_count', - string='Equipment Count') - - equipment_ids = fields.One2many(comodel_name='bemade_fsm.equipment', - inverse_name='equipment_location_id', - string='Equipments') - - @api.depends('equipment_ids') - def _compute_equipment_count(self): - for rec in self: - all_equipmemt_ids = self.env['bemade_fsm.equipment'].search([('equipment_location_id', '=', rec.id)]) - rec.equipment_count = len(all_equipmemt_ids) - - class Equipment(models.Model): _name = 'bemade_fsm.equipment' _rec_name = 'complete_name' @@ -68,35 +37,26 @@ class Equipment(models.Model): tracking=True, help="Classify and analyze your equipment categories like: Boiler, Laboratory, " "Waste water, Pure water") - partner_id = fields.Many2one('res.partner', string="Owner", - tracking=True, - domain="[('is_company', '=', True)]", - required=True) - + compute="_compute_partner") description = fields.Text(string="Description", - tracking=True, - ) + tracking=True) partner_location_id = fields.Many2one('res.partner', - string="Physical Location", - tracking=True, - domain="[('parent_id', '=', partner_id), ('is_site', '=', 'True')]", - required=True) - - equipment_location_id = fields.Many2one('bemade_fsm.equipment.location', - string="Location", - tracking=True, - domain="[('partner_id', '=', partner_location_id)]") + string="Physical Address", + tracking=True,) location_notes = fields.Text(string="Physical Location Notes", - tracking=True, - ) + tracking=True) + task_ids = fields.One2many(comodel_name='project.task', + inverse_name='equipment_id', + string='Interventions') - intervention_ids = fields.One2many(comodel_name='project.task', - inverse_name='equipment_id', - string='Interventions') + @api.depends('partner_location_id') + def _compute_partner(self): + for rec in self: + rec.partner_id = rec.partner_location_id and rec.partner_location_id.get_root_ancestor() @api.depends('pid_tag', 'name') def _compute_complete_name(self): @@ -108,12 +68,23 @@ class Equipment(models.Model): args = args or [] if name: equipments = self.search([ - '|', '|', '|', - ('pid_tag', operator, name), - ('name', operator, name), - ('partner_id.name', operator, name), - ('partner_location_id.name', operator, name)], + '|', '|', '|', + ('pid_tag', operator, name), + ('name', operator, name), + ('partner_id.name', operator, name), + ('partner_location_id.name', operator, name)], limit=limit) else: equipments = self.search(args, limit=limit) return equipments.name_get() + + def action_view_equipment(self): + return { + 'name': 'Equipment', + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': self.id, + 'context': self.env.context, + 'res_model': 'bemade_fsm.equipment', + 'type': 'ir.actions.act_window', + } \ No newline at end of file diff --git a/models/res_partner.py b/models/res_partner.py index ab516d3..574a0f2 100644 --- a/models/res_partner.py +++ b/models/res_partner.py @@ -1,5 +1,4 @@ -from odoo import api, fields, models - +from odoo import api, fields, models, Command class Partner(models.Model): _inherit = 'res.partner' @@ -7,26 +6,37 @@ class Partner(models.Model): equipment_count = fields.Integer(compute='_compute_equipment_count', string='Equipment Count') + owned_equipment_ids = fields.One2many(comodel_name="bemade_fsm.equipment", + inverse_name="partner_id", + string="Owned Equipments") + + equipment_ids = fields.One2many(comodel_name='bemade_fsm.equipment', - inverse_name='partner_id', - string='Equipments') - - equipment_location_count = fields.Integer(compute='_compute_equipment_location_count', - string='Equipment Location Count') - - equipment_location_ids = fields.One2many(comodel_name='bemade_fsm.equipment.location', - inverse_name='partner_id', - string='Equipment Location') - - is_site = fields.Boolean(string='Is an Equipment Site', - tracking=True, - default=False, - help="Check if the contact is an equipment site, otherwise it is not in that list") + inverse_name='partner_location_id', + string='Site Equipment') is_site_contact = fields.Boolean(string='Is a site contact', - tracking=True, - default=False, - help="Check if the contact is a site contact, otherwise it is a not in that list") + compute="_compute_is_site_contact") + + site_ids = fields.Many2many(string='Work Sites', + comodel_name='res.partner', + relation='res_partner_site_contact_rel', + column1='site_contact_id', + column2='site_id', + tracking=True) + + site_contacts = fields.Many2many(string='Site Contacts', + comodel_name='res.partner', + relation='res_partner_site_contact_rel', + column1='site_id', + column2='site_contact_id', + domain=[('is_company', '=', False)], + tracking=True) + + @api.depends('site_ids') + def _compute_is_site_contact(self): + for rec in self: + rec.is_site_contact = rec.site_ids is not False @api.depends('equipment_ids') def _compute_equipment_count(self): @@ -34,8 +44,12 @@ class Partner(models.Model): all_equipmemt_ids = self.env['bemade_fsm.equipment'].search([('partner_id', '=', rec.id)]) rec.equipment_count = len(all_equipmemt_ids) - @api.depends('equipment_location_ids') - def _compute_equipment_location_count(self): - for rec in self: - all_equipmemt_location_ids = self.env['bemade_fsm.equipment.location'].search([('partner_id', '=', rec.id)]) - rec.equipment_location_count = len(all_equipmemt_location_ids) + def get_root_ancestor(self): + """ Returns the partner at the top of the parent-child hierarchy. """ + self.ensure_one() + return self.parent_id and self.parent_id.get_root_ancestor() or self + + def get_first_company_ancestor(self): + """ Returns the first ancestor that is a company """ + self.ensure_one() + return self.is_company and self or self.parent_id and self.parent_id.get_first_company_ancestor() diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index 086f935..82eb4f7 100644 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -3,5 +3,4 @@ access_bemade_fsm_task_template,bemade_fsm_task_template,model_project_task_temp access_bemade_fsm_task_template,bemade_fsm_task_template,model_project_task_template,project.group_project_user,1,1,1,1 access_bemade_fsm_equipment,bemade_fsm_equipment,model_bemade_fsm_equipment,base.group_user,1,1,1,1 access_bemade_fsm_equipment_tag,bemade_fsm_equipment_tag,model_bemade_fsm_equipment_tag,base.group_user,1,1,1,1 -access_bemade_fsm_equipment_type,access_bemade_fsm_equipment_type,model_bemade_fsm_equipment_type,base.group_user,1,0,0,0 -access_bemade_fsm_equipment_location,access_bemade_fsm_equipment_location,model_bemade_fsm_equipment_location,base.group_user,1,0,0,0 \ No newline at end of file +access_bemade_fsm_equipment_type,access_bemade_fsm_equipment_type,model_bemade_fsm_equipment_type,base.group_user,1,0,0,0 \ No newline at end of file diff --git a/static/tests/tours/task_equipment_tour.js b/static/tests/tours/task_equipment_tour.js new file mode 100644 index 0000000..8abdd1d --- /dev/null +++ b/static/tests/tours/task_equipment_tour.js @@ -0,0 +1,14 @@ +/** @odoo-module **/ + +// Navigate to the Service > Clients > Equipment menu +// Click the Create button +// Fill in the required fields, including creating a new Client Location and PID Tag +// Navigate to the client location, then to the client, making sure that the equipment and client location links appear + +// Now make another one, but from the Partner interface +// Navigate to Service > Clients > Clients +// Search for and open the test client +// On the "Locations" tab, add a location +// Open the location and add a new Equipment to its equipment list + +// Create a task in the test project diff --git a/tests/__init__.py b/tests/__init__.py index 9df0958..a66b934 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,2 +1,4 @@ +from . import test_bemade_fsm_common from . import test_task_template from . import test_task_template_sale_order +from . import test_equipment diff --git a/tests/test_bemade_fsm_common.py b/tests/test_bemade_fsm_common.py new file mode 100644 index 0000000..1d74b7a --- /dev/null +++ b/tests/test_bemade_fsm_common.py @@ -0,0 +1,42 @@ +from odoo.tests.common import TransactionCase, HttpCase, tagged +from odoo.tools import mute_logger +from odoo.exceptions import MissingError +from odoo import Command +from psycopg2.errors import ForeignKeyViolation + + +class FSMManagerUserTransactionCase(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + user_group_employee = cls.env.ref('base.group_user') + user_group_project_user = cls.env.ref('project.group_project_user') + user_group_project_manager = cls.env.ref('project.group_project_manager') + user_group_fsm_user = cls.env.ref('industry_fsm.group_fsm_user') + user_group_fsm_manager = cls.env.ref('industry_fsm.group_fsm_manager') + user_group_sales_manager = cls.env.ref('sales_team.group_sale_manager') + user_group_sales_user = cls.env.ref('sales_team.group_sale_salesman') + user_product_customer = cls.env.ref('customer_product_code.group_product_customer_code_user') + + group_ids = [user_group_employee, + user_group_project_user, + user_group_project_manager, + user_group_fsm_user, + user_group_fsm_manager, + user_group_sales_user, + user_group_sales_manager, ] + if user_product_customer: + group_ids.append(user_product_customer) + + # Test user with project access rights for the various tests + Users = cls.env['res.users'].with_context({'no_reset_password': True}) + cls.user = Users.create({ + 'name': 'Project Manager', + 'login': 'misterpm', + 'password': 'misterpm', + 'email': 'mrpm@testco.com', + 'signature': 'Mr. PM', + 'groups_id': [(6, 0, [user_group_employee.id, user_group_project_user.id, user_group_project_manager.id, + user_group_sales_user.id])], + }) diff --git a/tests/test_equipment.py b/tests/test_equipment.py new file mode 100644 index 0000000..0920878 --- /dev/null +++ b/tests/test_equipment.py @@ -0,0 +1,32 @@ +from odoo.tests.common import HttpCase, tagged +from odoo.tools import mute_logger +from odoo.exceptions import MissingError +from odoo import Command +from psycopg2.errors import ForeignKeyViolation +from .test_bemade_fsm_common import FSMManagerUserTransactionCase + +class TestEquipmentCommon(FSMManagerUserTransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + # Set up the test partner + cls.partner_company = cls.env['res.partner'].create({ + 'name': 'Test Partner Company', + 'company_type': 'company', + 'street': '123 Street St.', + 'city': 'Montreal', + 'state_id': cls.env['res.country.state'].search([('name','ilike','Quebec%')]), + 'country_id': cls.env['res.country'].search([('name','=','Canada')]) + }) + + cls.partner_contact = cls.env['res.partner'].create({ + 'name': 'Site Contact', + 'company_type': 'person', + 'parent_id': cls.partner_company.id, + }) + + cls.equipment = cls.env['bemade_fsm.equipment'].create({ + 'name': 'Test Equipment 1', + }) \ No newline at end of file diff --git a/tests/test_task_template.py b/tests/test_task_template.py index ad84734..ec42aca 100644 --- a/tests/test_task_template.py +++ b/tests/test_task_template.py @@ -1,38 +1,16 @@ -from odoo.tests.common import TransactionCase, HttpCase, tagged +from .test_bemade_fsm_common import FSMManagerUserTransactionCase +from odoo.tests.common import HttpCase, tagged from odoo.tools import mute_logger from odoo.exceptions import MissingError from odoo import Command from psycopg2.errors import ForeignKeyViolation -class TestTaskTemplateCommon(TransactionCase): +class TestTaskTemplateCommon(FSMManagerUserTransactionCase): @classmethod def setUpClass(cls): super().setUpClass() - user_group_employee = cls.env.ref('base.group_user') - user_group_project_user = cls.env.ref('project.group_project_user') - user_group_project_manager = cls.env.ref('project.group_project_manager') - user_group_sales_manager = cls.env.ref('sales_team.group_sale_manager') - user_group_sales_user = cls.env.ref('sales_team.group_sale_salesman') - user_product_customer = cls.env.ref('customer_product_code.group_product_customer_code_user') - - group_ids = [user_group_employee, user_group_project_user, user_group_project_manager, user_group_sales_user, - user_group_sales_manager] - if user_product_customer: - group_ids.append(user_product_customer) - - # Test user with project access rights for the various tests - Users = cls.env['res.users'].with_context({'no_reset_password': True}) - cls.user = Users.create({ - 'name': 'Project Manager', - 'login': 'misterpm', - 'password': 'misterpm', - 'email': 'mrpm@testco.com', - 'signature': 'Mr. PM', - 'groups_id': [(6, 0, [user_group_employee.id, user_group_project_user.id, user_group_project_manager.id, - user_group_sales_user.id])], - }) hours_uom = cls.env['uom.uom'].search([('name', '=', 'Hour')]) or False # Test product to use with the various tests cls.task1 = cls.env['project.task.template'].create({ diff --git a/views/equipment.xml b/views/equipment.xml index 505d613..4047df6 100644 --- a/views/equipment.xml +++ b/views/equipment.xml @@ -20,7 +20,6 @@ groups="sale.group_delivery_invoice_address" context="{'default_type': 'delivery', 'show_address': 1}" options='{"always_reload": True}'/> - diff --git a/views/equipment_location.xml b/views/equipment_location.xml deleted file mode 100644 index 9f2cd0b..0000000 --- a/views/equipment_location.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - bemade_fsm.partner.equipment.location.form - res.partner - - - - - - - - - - - -
-
- - -
-
-
-
-
-
-
-
-
-
- - - bemade_fsm.equipment.location.form - bemade_fsm.equipment.location - -
- - - - - - - - - - - - - - - - - - -
- - - -
-
-
-
- - - bemade_fsm.equipment.location.tree - bemade_fsm.equipment.location - - - - - - - - - - - bemade_fsm.equipment.location.search - bemade_fsm.equipment.location - - - - - - - - - - - - - - Equipment Location - bemade_fsm.equipment.location - tree,form - -
diff --git a/views/menus.xml b/views/menus.xml new file mode 100644 index 0000000..76c5464 --- /dev/null +++ b/views/menus.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/views/res_partner.xml b/views/res_partner.xml index 165a83f..d451cb9 100644 --- a/views/res_partner.xml +++ b/views/res_partner.xml @@ -8,29 +8,63 @@ [("partner_id", "=", active_id)] - - res.partner.view.buttons.fso + + bemade_fsm.partner.equipment.location.form res.partner - - + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/views/task_views.xml b/views/task_views.xml new file mode 100644 index 0000000..6d2ccce --- /dev/null +++ b/views/task_views.xml @@ -0,0 +1,16 @@ + + + + + bemade_fsm.project_task.form + project.task + + + + + + + + + + \ No newline at end of file