separated equipment out of bemade_fsm into fsm_equipment module

This commit is contained in:
Marc Durepos 2024-08-20 15:58:17 -04:00
parent d94fabf8ba
commit 382b573a86
28 changed files with 302 additions and 265 deletions

View file

@ -36,13 +36,13 @@
"industry_fsm_stock",
"industry_fsm_report",
"industry_fsm_sale_report",
"fsm_equipment",
"bemade_partner_root_ancestor",
"mail",
],
"data": [
"data/fsm_data.xml",
"views/task_template_views.xml",
"views/equipment.xml",
"security/ir.model.access.csv",
"views/product_views.xml",
"views/res_partner.xml",

View file

@ -2,9 +2,6 @@ from . import task_template
from . import product_template
from . import sale_order_line
from . import sale_order
from . import equipment
from . import equipment_type
from . import equipment_tag
from . import task
from . import res_partner
from . import fsm_visit

View file

@ -1,9 +0,0 @@
from odoo import fields, models
class EquipmentType(models.Model):
_name = "bemade_fsm.equipment.type"
_description = "Field service equipment type"
_order = "id"
name = fields.Char(string="Intervention Name", required=True, translate=True)

View file

@ -40,7 +40,7 @@ class FSMVisit(models.Model):
)
summarized_equipment_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
string="Equipment to Service",
compute="_compute_summarized_equipment_ids",
)

View file

@ -4,20 +4,6 @@ from odoo import api, fields, models
class Partner(models.Model):
_inherit = "res.partner"
equipment_count = fields.Integer(compute="_compute_equipment_count")
owned_equipment_ids = fields.One2many(
comodel_name="bemade_fsm.equipment",
compute="_compute_owned_equipment_ids",
string="Owned Equipments",
)
equipment_ids = fields.One2many(
comodel_name="bemade_fsm.equipment",
inverse_name="partner_location_id",
string="Site Equipment",
)
is_site_contact = fields.Boolean(
string="Is a site contact",
compute="_compute_is_site_contact",
@ -52,33 +38,11 @@ class Partner(models.Model):
tracking=True,
)
is_service_site = fields.Boolean(
compute="_compute_is_service_site",
)
@api.depends("equipment_ids", "child_ids.company_type", "child_ids.equipment_ids")
def _compute_owned_equipment_ids(self):
for rec in self:
ids = rec.equipment_ids | rec.child_ids.mapped("equipment_ids")
rec.owned_equipment_ids = ids or False
@api.depends("site_ids")
def _compute_is_site_contact(self):
for rec in self:
rec.is_site_contact = rec.site_ids
@api.depends("equipment_ids")
def _compute_equipment_count(self):
for rec in self:
all_equipment_ids = self.env["bemade_fsm.equipment"].search(
[("partner_location_id", "=", rec.id)]
)
rec.equipment_count = len(all_equipment_ids)
@api.model
def _search_is_site_contact(self, operator, value):
return [("site_ids", "!=", False)]
def _compute_is_service_site(self):
for rec in self:
rec.is_service_site = bool(rec.equipment_ids)

View file

@ -5,11 +5,11 @@ class SaleOrder(models.Model):
_inherit = "sale.order"
valid_equipment_ids = fields.One2many(
comodel_name="bemade_fsm.equipment", related="partner_id.owned_equipment_ids"
comodel_name="fsm.equipment", related="partner_id.owned_equipment_ids"
)
default_equipment_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
string="Default Equipment to Service",
help="The default equipment to service for new sale order lines.",
compute="_compute_default_equipment",
@ -18,7 +18,7 @@ class SaleOrder(models.Model):
)
summary_equipment_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
string="Equipment Being Serviced",
compute="_compute_summary_equipment_ids",
)
@ -106,8 +106,9 @@ class SaleOrder(models.Model):
return rec
def _create_default_visit(self):
"""Called when an order is confirmed with lines that will create an FSM task, in order to make sure there is
a visit line grouping all the service being done."""
"""Called when an order is confirmed with lines that will create an FSM task,
in order to make sure there is a visit line grouping all the service being done.
"""
self.ensure_one()
visit = self.env["bemade_fsm.visit"].create(
{
@ -119,8 +120,8 @@ class SaleOrder(models.Model):
visit.so_section_id.sequence = 0
def _create_or_organize_visits_if_needed(self):
"""Adds a visit line to the top of the order if there are not already visit lines for an order with lines that
will create an FSM task."""
"""Adds a visit line to the top of the order if there are not already visit
lines for an order with lines that will create an FSM task."""
for order in self.filtered("company_id.create_default_fsm_visit"):
if not order.visit_ids and order.is_fsm:
order._create_default_visit()

View file

@ -4,7 +4,7 @@ from odoo import fields, models, api, _, Command
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
valid_equipment_ids = fields.One2many(
comodel_name="bemade_fsm.equipment", related="order_id.valid_equipment_ids"
comodel_name="fsm.equipment", related="order_id.valid_equipment_ids"
)
visit_ids = fields.One2many(
@ -42,7 +42,7 @@ class SaleOrderLine(models.Model):
equipment_ids = fields.Many2many(
string="Equipment to Service",
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
relation="bemade_fsm_equipment_sale_order_line_rel",
column1="sale_order_line_id",
column2="equipment_id",

View file

@ -7,7 +7,7 @@ class Task(models.Model):
_inherit = "project.task"
equipment_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
relation="bemade_fsm_task_equipment_rel",
column1="task_id",
column2="equipment_id",
@ -59,6 +59,11 @@ class Task(models.Model):
compute="_compute_is_closed",
)
root_ancestor = fields.Many2one(
comodel_name="project.task",
compute="_compute_root_ancestor",
)
def _compute_is_closed(self):
for rec in self:
rec.is_closed = rec.state in CLOSED_STATES
@ -213,6 +218,7 @@ class Task(models.Model):
else:
rec.name = title
@property
def root_ancestor(self):
return self.parent_id and self.parent_id.root_ancestor or self
@api.depends("parent_id", "parent_id.root_ancestor")
def _compute_root_ancestor(self):
for rec in self:
rec.root_ancestor = rec.parent_id and rec.parent_id.root_ancestor or self

View file

@ -58,7 +58,7 @@ class TaskTemplate(models.Model):
planned_hours = fields.Float("Initially Planned Hours")
equipment_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment",
comodel_name="fsm.equipment",
relation="bemade_fsm_task_template_equipment_rel",
column1="task_template_id",
column2="equipment_id",
@ -78,9 +78,7 @@ class TaskTemplate(models.Model):
def _onchange_customer(self):
for rec in self:
new_equipment_ids = [
eq.id
for eq in rec.equipment_ids
if eq.partner_location_id == rec.customer
eq.id for eq in rec.equipment_ids if eq.partner_id == rec.customer
]
rec.write({"equipment_ids": [Command.set(new_equipment_ids)]})
@ -107,7 +105,8 @@ class TaskTemplate(models.Model):
return vals
def create_task_from_self(self, project, name=False, parent_id=False):
"""Create a project.task from this template and return it. Can be called on a RecordSet of multiple templates.
"""Create a project.task from this template and return it.
Can be called on a RecordSet of multiple templates.
:param project: project.project record the task should be added to
:param name: name for the new task (defaults to template name)

View file

@ -1,8 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_bemade_fsm_task_template_manager,bemade_fsm_task_template,model_project_task_template,project.group_project_manager,1,1,1,1
access_bemade_fsm_task_template_user,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_visit,access_bemade_fsm_visit,model_bemade_fsm_visit,base.group_user,1,1,1,1
access_bemade_fsm_task_wizard,access_bemade_fsm_task_wizard,model_project_task_from_template_wizard,project.group_project_user,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_bemade_fsm_task_template_manager bemade_fsm_task_template model_project_task_template project.group_project_manager 1 1 1 1
3 access_bemade_fsm_task_template_user 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
4 access_bemade_fsm_visit access_bemade_fsm_visit model_bemade_fsm_visit base.group_user 1 1 1 1
5 access_bemade_fsm_task_wizard access_bemade_fsm_task_wizard model_project_task_from_template_wizard project.group_project_user 1 1 1 1

View file

@ -1,7 +1,6 @@
from . import test_bemade_fsm_common
from . import test_task_template
from . import test_sale_order
from . import test_equipment
from . import test_fsm_contact_setting
from . import test_fsm_visit
from . import test_task

View file

@ -69,7 +69,8 @@ class BemadeFSMBaseTest(TransactionCase):
"""Generates a partner with basic address filled in.
:param name: The partner's name.
:param company_type: The type of partner, either 'company' or 'person' are accepted.
:param company_type: The type of partner, either 'company' or 'person' are
accepted.
"""
return cls.env["res.partner"].create(
{
@ -119,10 +120,10 @@ class BemadeFSMBaseTest(TransactionCase):
@classmethod
def _generate_equipment(cls, name="test equipment", partner=None):
return cls.env["bemade_fsm.equipment"].create(
return cls.env["fsm.equipment"].create(
{
"name": name,
"partner_location_id": partner and partner.id or False,
"partner_id": partner and partner.id or False,
}
)
@ -186,14 +187,18 @@ class BemadeFSMBaseTest(TransactionCase):
):
"""Generates a task template with the specified structure and naming.
:param parent: The parent task template for the top-level task template being generated
:param structure: A list of integers describing the number of tasks for each level of descendants. An empty
list represents only one top-level task template. If no structure is given, an empty list
will be used in its place.
:param names: The name prefixes to be given to the task templates at each level. Each prefix will be followed
by a sequential integer for its level. Child 1, Child 2, Grandchild 1, etc. If no names argument
:param parent: The parent task template for the top-level task template being
generated
:param structure: A list of integers describing the number of tasks for each
level of descendants. An empty list represents only one
top-level task template. If no structure is given, an empty
list will be used in its place.
:param names: The name prefixes to be given to the task templates at each level.
Each prefix will be followed by a sequential integer for its
level. Child 1, Child 2, Grandchild 1, etc. If no names argument
is passed, a default ['Task Template'] argument will be used.
:param planned_hours: The number of planned hours for the top-level task template being generated.
:param planned_hours: The number of planned hours for the top-level task
template being generated.
:param equipment: The equipment to add as linked equipment to the task template.
"""
if not names:

View file

@ -1,21 +0,0 @@
from odoo.tests.common import tagged
from .test_bemade_fsm_common import BemadeFSMBaseTest
from odoo import Command
from odoo.exceptions import MissingError
@tagged("-at_install", "post_install")
class TestEquipment(BemadeFSMBaseTest):
def test_crud(self):
partner_company = self._generate_partner()
self._generate_partner("Site Contact", "person", partner_company)
equipment = self._generate_equipment("Test Equipment 1", partner_company)
# Just make sure the basic ORM stuff is OK
self.assertTrue(equipment in partner_company.equipment_ids)
self.assertTrue(len(partner_company.equipment_ids) == 1)
# Delete should cascade
partner_company.write({"equipment_ids": [Command.set([])]})
with self.assertRaises(MissingError):
_ = equipment.name

View file

@ -15,7 +15,8 @@ class SaleOrderFSMContactsCase(BemadeFSMBaseTest):
so = self._generate_sale_order(parent_co)
self.assertTrue(so.site_contacts == parent_co.site_contacts)
# Make sure updating the site contacts on the SO doesn't feed back to the partner
# Make sure updating the site contacts on the SO doesn't feed back to the
# partner
so.write({"site_contacts": [Command.set([contact_1.id])]})
self.assertTrue(contact_1 in so.site_contacts)
self.assertTrue(contact_2 not in so.site_contacts)
@ -39,7 +40,8 @@ class SaleOrderFSMContactsCase(BemadeFSMBaseTest):
self.assertTrue(contact_1 in so.work_order_contacts)
self.assertTrue(contact_2 in so.work_order_contacts)
# Make sure setting the work order contacts on the SO doesn't feed back to the partner
# Make sure setting the work order contacts on the SO doesn't feed back to the
# partner
so.write({"work_order_contacts": [Command.set([contact_1.id])]})
self.assertTrue(contact_1 in so.work_order_contacts)
self.assertTrue(contact_2 not in so.work_order_contacts)
@ -119,7 +121,8 @@ class SaleOrderFSMContactsCase(BemadeFSMBaseTest):
self.assertFalse(so.work_order_contacts)
self.assertFalse(so.site_contacts)
# Now set back to the location with the FSM contacts and make sure they get set on the SO
# Now set back to the location with the FSM contacts and make sure they get set
# on the SO
form.partner_shipping_id = shipping_location
form.save()
self.assertEqual(so.work_order_contacts, shipping_location.work_order_contacts)

View file

@ -7,7 +7,8 @@ from odoo import Command
class TaskTest(BemadeFSMBaseTest):
@classmethod
def setUpClass(cls):
# Chose to set up all tests the same way since this code was becoming very redundant
# Chose to set up all tests the same way since this code was becoming very
# redundant
super().setUpClass()
cls.user = cls._generate_project_manager_user("Bob", "Bob")
@ -62,7 +63,8 @@ class TaskTest(BemadeFSMBaseTest):
self.assertFalse(
any([t.propagate_assignment for t in task._get_all_subtasks()])
)
# Then, test that assigning the parent only assigns its children, not its grandchildren
# Then, test that assigning the parent only assigns its children, not its
# grandchildren
task.write({"user_ids": [Command.set([])]})
self.assertTrue(all([not t.user_ids for t in task | task.child_ids]))
self.assertTrue(

View file

@ -14,27 +14,4 @@
parent="industry_fsm.fsm_menu_root"
groups="project.group_project_manager,industry_fsm.group_fsm_manager"
/>
<menuitem
id="menu_service_client"
name="Clients"
sequence="10"
parent="industry_fsm.fsm_menu_root"
groups="industry_fsm.group_fsm_user"
/>
<menuitem
id="menu_service_client_clients"
name="Clients"
action="base.action_partner_customer_form"
sequence="20"
parent="menu_service_client"
groups="industry_fsm.group_fsm_user"
/>
<menuitem
id="menu_service_client_equipment"
name="Client Equipment"
action="action_window_equipment"
sequence="21"
parent="menu_service_client"
groups="industry_fsm.group_fsm_user"
/>
</odoo>

View file

@ -1,45 +1,15 @@
<?xml version="1.0" ?>
<odoo>
<record id="act_res_partner_2_equipment" model="ir.actions.act_window">
<field name="name">Equipments</field>
<field name="res_model">bemade_fsm.equipment</field>
<field name="view_mode">tree,form</field>
<field name="context">{'default_partner_location_id': active_id}</field>
<field name="domain">[("partner_location_id", "=", active_id)]</field>
</record>
<record id="partner_equipment_location_view_form" model="ir.ui.view">
<field name="name">bemade_fsm.partner.equipment.location.form</field>
<field name="name">partner.equipment.location.view.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field
name="inherit_id"
ref="fsm_equipment.partner_equipment_location_view_form"
/>
<field name="arch" type="xml">
<xpath expr="//page[@name='internal_notes']" position="before">
<field name="is_site_contact" invisible="True" />
<field name="is_service_site" invisible="True" />
<page
name="field_service"
string="Service Site Responsibilities"
invisible="is_service_site or is_company"
>
<field name="owned_equipment_ids" invisible="True" />
<group>
<field name="site_ids">
<tree editable="bottom">
<field name="name" widget="res_partner_many2one" />
</tree>
</field>
</group>
</page>
<page
name="service_equipment"
string="Service Site Info"
invisible="is_site_contact"
>
<field
name="equipment_ids"
context="{'tree_view_ref': 'bemade_fsm.fsm_equipment_view_tree'}"
readonly="False"
/>
<page name="equipment" position="after">
<page name="Service Contacts" invisible="not is_company">
<field
name="site_contacts"
context="{'tree_view_ref': 'bemade_fsm.fsm_contacts_view_tree'}"
@ -47,36 +17,18 @@
<field
name="work_order_contacts"
context="{'tree_view_ref': 'bemade_fsm.fsm_contacts_view_tree'}"
/>
<field
name="owned_equipment_ids"
context="{'tree_view_ref': 'bemade_fsm.fsm_equipment_view_tree'}"
readonly="True"
/>
</page>
</xpath>
<div name="button_box" position="inside">
<button
class="oe_stat_button"
type="action"
name="%(bemade_fsm.act_res_partner_2_equipment)d"
icon="fa-tachometer"
>
<field
string="Equipments"
name="equipment_count"
widget="statinfo"
/>
</button>
</div>
<field name="lang" position="after">
</field>
<xpath
expr="/form//field[@name='child_ids']/form//field[@name='comment']"
position="after"
>
<field name="is_site_contact" />
</xpath>
<page name="Service Sites" invisible="is_company">
<group>
<field name="site_ids">
<tree editable="bottom">
<field name="name" widget="res_partner_many2one" />
</tree>
</field>
</group>
</page>
</page>
</field>
</record>
<record id="fsm_contacts_view_tree" model="ir.ui.view">
@ -91,21 +43,4 @@
</tree>
</field>
</record>
<record id="fsm_equipment_view_tree" model="ir.ui.view">
<field name="name">bemade_fsm.equipment.tree</field>
<field name="model">bemade_fsm.equipment</field>
<field name="arch" type="xml">
<tree>
<field name="pid_tag" />
<field name="name" />
<field name="location_notes" />
<button
name="action_view_equipment"
type="object"
string="Details"
icon="fa-external-link"
/>
</tree>
</field>
</record>
</odoo>

View file

@ -23,8 +23,8 @@
<field name="customer" />
<field
name="equipment_ids"
domain="[('partner_location_id', '=', customer)]"
context="{'tree_view_ref': 'bemade_fsm.equipment_view_tree'}"
domain="[('partner_id', '=', customer)]"
context="{'tree_view_ref': 'fsm_equipment.equipment_view_tree'}"
/>
<field name="tags" widget="many2many_tags" />
<field name="company_id" />

View file

@ -19,8 +19,8 @@
<group name="equipment_and_contacts">
<field
name="equipment_ids"
domain="[('partner_location_id', '=', partner_id)]"
context="{'tree_view_ref': 'bemade_fsm.equipment_view_tree'}"
domain="[('partner_id', '=', partner_id)]"
context="{'tree_view_ref': 'fsm_equipment.equipment_view_tree'}"
/>
<field
name="site_contacts"

View file

@ -0,0 +1 @@
from . import models

View file

@ -0,0 +1,37 @@
#
# Bemade Inc.
#
# Copyright (C) 2023-June Bemade Inc. (<https://www.bemade.org>).
# Author: Marc Durepos (Contact : marc@bemade.org)
#
# This program is under the terms of the GNU Lesser General Public License,
# version 3.
#
# For full license details, see https://www.gnu.org/licenses/lgpl-3.0.en.html.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
{
"name": "FSM Equipment",
"version": "17.0.0.1.0",
"summary": "Add the notion of client equipment for Field Service",
"category": "Services/Field Service",
"author": "Bemade Inc.",
"website": "http://www.bemade.org",
"license": "LGPL-3",
"depends": ["industry_fsm", "account"],
"data": [
"security/ir.model.access.csv",
"views/equipment_views.xml",
"views/res_partner_views.xml",
],
"assets": {},
"installable": True,
"auto_install": False,
}

View file

@ -0,0 +1,3 @@
from . import equipment_tag
from . import equipment
from . import res_partner

View file

@ -1,39 +1,39 @@
from odoo import api, fields, models
from odoo import models, fields, api, _
class Equipment(models.Model):
_name = "bemade_fsm.equipment"
_rec_name = "complete_name"
_description = "Field service equipment"
_name = "fsm.equipment"
_description = "Partner-Owned Equipment"
_inherit = ["mail.thread", "mail.activity.mixin"]
pid_tag = fields.Char(string="P&ID Tag", tracking=True)
name = fields.Char(tracking=True, required=True)
complete_name = fields.Char(
string="Equipment Name", compute="_compute_complete_name", store=True
code = fields.Char(
tracking=True,
)
name = fields.Char(
tracking=True,
required=True,
)
tag_ids = fields.Many2many(
comodel_name="bemade_fsm.equipment.tag",
string="Application",
help=(
"Classify and analyze your equipment categories like: Boiler, Laboratory,"
" Waste water, Pure water"
),
comodel_name="fsm.equipment.tag",
string="Tags",
)
description = fields.Text(tracking=True)
partner_location_id = fields.Many2one(
partner_id = fields.Many2one(
comodel_name="res.partner",
string="Physical Address",
tracking=True,
ondelete="cascade",
)
location_notes = fields.Text(string="Physical Location Notes", tracking=True)
location_notes = fields.Text(
string="Physical Location Notes",
tracking=True,
help="Any useful information about physical location "
"(door codes, directions, etc.).",
)
task_ids = fields.Many2many(
comodel_name="project.task",
@ -45,13 +45,6 @@ class Equipment(models.Model):
active = fields.Boolean(default=True)
@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.root_ancestor
)
@api.model
def name_search(self, name="", args=None, operator="ilike", limit=100):
args = args or []
@ -60,9 +53,9 @@ class Equipment(models.Model):
[
"|",
"|",
("pid_tag", operator, name),
("code", operator, name),
("name", operator, name),
("partner_location_id.name", operator, name),
("partner_id.name", operator, name),
],
limit=limit,
)
@ -77,13 +70,13 @@ class Equipment(models.Model):
"view_mode": "form",
"res_id": self.id,
"context": self.env.context,
"res_model": "bemade_fsm.equipment",
"res_model": "fsm.equipment",
"type": "ir.actions.act_window",
}
@api.depends("pid_tag", "name")
@api.depends("code", "name")
def _compute_complete_name(self):
for rec in self:
tag_part = "[%s] " % rec.pid_tag if rec.pid_tag else ""
tag_part = "[%s] " % rec.code if rec.code else ""
name = rec.name or ""
rec.complete_name = tag_part + name

View file

@ -2,11 +2,17 @@ from odoo import fields, models
class EquipmentTag(models.Model):
_name = "bemade_fsm.equipment.tag"
_name = "fsm.equipment.tag"
_description = "Field service equipment category"
name = fields.Char(required=True, translate=True)
color = fields.Integer("Color Index", default=10)
name = fields.Char(
required=True,
translate=True,
)
color = fields.Integer(
"Color Index",
default=10,
)
_sql_constraints = [
("name_uniq", "unique (name)", "Tag name already exists !"),

View file

@ -0,0 +1,47 @@
from odoo import models, fields, api
class Partner(models.Model):
_inherit = "res.partner"
equipment_count = fields.Integer(compute="_compute_equipment_count")
owned_equipment_ids = fields.One2many(
comodel_name="fsm.equipment",
compute="_compute_owned_equipment_ids",
string="Owned Equipments",
)
equipment_ids = fields.One2many(
comodel_name="fsm.equipment",
inverse_name="partner_id",
string="Site Equipment",
)
is_service_site = fields.Boolean(
compute="_compute_is_service_site",
help="A partner is a service site if it has one or more equipments.",
)
@api.depends(
"equipment_ids",
"child_ids.company_type",
"child_ids.equipment_ids",
)
def _compute_owned_equipment_ids(self):
for rec in self:
ids = rec.equipment_ids | rec.child_ids.mapped("equipment_ids")
rec.owned_equipment_ids = ids or False
@api.depends("equipment_ids")
def _compute_equipment_count(self):
for rec in self:
all_equipment_ids = self.env["fsm.equipment"].search(
[("partner_id", "=", rec.id)]
)
rec.equipment_count = len(all_equipment_ids)
@api.depends("equipment_ids")
def _compute_is_service_site(self):
for rec in self:
rec.is_service_site = bool(rec.equipment_ids)

View file

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_fsm_equipment,fsm_equipment,model_fsm_equipment,base.group_user,1,1,1,1
access_fsm_equipment_tag,fsm_equipment_tag,model_fsm_equipment_tag,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_fsm_equipment fsm_equipment model_fsm_equipment base.group_user 1 1 1 1
3 access_fsm_equipment_tag fsm_equipment_tag model_fsm_equipment_tag base.group_user 1 1 1 1

View file

@ -2,23 +2,26 @@
<odoo>
<!-- Equipment Form View -->
<record id="equipment_view_form" model="ir.ui.view">
<field name="name">bemade_fsm.equipment.form</field>
<field name="model">bemade_fsm.equipment</field>
<field name="name">fsm.equipment.form</field>
<field name="model">fsm.equipment</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<group name="left">
<field name="pid_tag" />
<field name="code" />
<field name="name" />
<field name="description" />
<field name="location_notes" />
</group>
<group name="right">
<field
name="partner_location_id"
name="partner_id"
groups="account.group_delivery_invoice_address"
context="{'default_type': 'delivery', 'show_address': 1}"
context="{
'default_type': 'delivery',
'show_address': 1
}"
options='{"always_reload": True}'
/>
<field
@ -28,22 +31,27 @@
/>
</group>
</group>
<notebook>
<page string="Interventions">
<field name="task_ids" groupby="root_ancestor" />
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="activity_ids" widget="mail_activity" />
<field name="message_ids" widget="mail_thread" />
<field name="message_follower_ids" />
<field name="activity_ids" />
<field name="message_ids" />
</div>
</form>
</field>
</record>
<record id="equipment_view_tree" model="ir.ui.view">
<field name="name">bemade_fsm.equipment.tree</field>
<field name="model">bemade_fsm.equipment</field>
<field name="name">fsm.equipment.tree</field>
<field name="model">fsm.equipment</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="pid_tag" />
<field name="code" />
<field name="name" />
<field name="description" />
<field
@ -51,21 +59,43 @@
widget="many2many_tags"
options="{'no_open': False}"
/>
<field name="partner_location_id" />
<field name="partner_id" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_window_equipment">
<field name="name">Equipment</field>
<field name="res_model">bemade_fsm.equipment</field>
<field name="res_model">fsm.equipment</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.actions.act_window" id="action_window_equipment_tags">
<field name="name">Equipment Tag</field>
<field name="res_model">bemade_fsm.equipment.tag</field>
<field name="res_model">fsm.equipment.tag</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_service_client"
name="Clients"
sequence="10"
parent="industry_fsm.fsm_menu_root"
groups="industry_fsm.group_fsm_user"
/>
<menuitem
id="menu_service_client_clients"
name="Clients"
action="base.action_partner_customer_form"
sequence="20"
parent="menu_service_client"
groups="industry_fsm.group_fsm_user"
/>
<menuitem
id="menu_service_client_equipment"
name="Client Equipment"
action="action_window_equipment"
sequence="21"
parent="menu_service_client"
groups="industry_fsm.group_fsm_user"
/>
</odoo>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="act_res_partner_2_equipment" model="ir.actions.act_window">
<field name="name">Partner Equipment</field>
<field name="res_model">fsm.equipment</field>
<field name="view_mode">tree,form</field>
<field name="context">{'default_partner_location_id': active_id}</field>
<field name="domain">[("partner_id", "=", active_id)]</field>
</record>
<record id="fsm_equipment_view_tree" model="ir.ui.view">
<field name="name">fsm.equipment.tree</field>
<field name="model">fsm.equipment</field>
<field name="arch" type="xml">
<tree>
<field name="code" />
<field name="name" />
<field name="location_notes" />
<button
name="action_view_equipment"
type="object"
string="Details"
icon="fa-external-link"
/>
</tree>
</field>
</record>
<record id="partner_equipment_location_view_form" model="ir.ui.view">
<field name="name">bemade_fsm.partner.equipment.location.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<xpath expr="//page[@name='internal_notes']" position="before">
<page name="equipment" string="Equipment">
<field
name="equipment_ids"
context="{'tree_view_ref': 'fsm_equipment.fsm_equipment_view_tree'}"
readonly="False"
/>
<field
name="owned_equipment_ids"
context="{'tree_view_ref': 'fsm_equipment.fsm_equipment_view_tree'}"
readonly="True"
/>
</page>
</xpath>
<div name="button_box" position="inside">
<button
class="oe_stat_button"
type="action"
name="%(fsm_equipment.act_res_partner_2_equipment)d"
icon="fa-tachometer"
>
<field
string="Equipments"
name="equipment_count"
widget="statinfo"
/>
</button>
</div>
</field>
</record>
</odoo>