separated equipment out of bemade_fsm into fsm_equipment module
This commit is contained in:
parent
d94fabf8ba
commit
382b573a86
28 changed files with 302 additions and 265 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
1
fsm_equipment/__init__.py
Normal file
1
fsm_equipment/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from . import models
|
||||
37
fsm_equipment/__manifest__.py
Normal file
37
fsm_equipment/__manifest__.py
Normal 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,
|
||||
}
|
||||
3
fsm_equipment/models/__init__.py
Normal file
3
fsm_equipment/models/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from . import equipment_tag
|
||||
from . import equipment
|
||||
from . import res_partner
|
||||
|
|
@ -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
|
||||
|
|
@ -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 !"),
|
||||
47
fsm_equipment/models/res_partner.py
Normal file
47
fsm_equipment/models/res_partner.py
Normal 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)
|
||||
3
fsm_equipment/security/ir.model.access.csv
Normal file
3
fsm_equipment/security/ir.model.access.csv
Normal 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
|
||||
|
|
|
@ -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>
|
||||
62
fsm_equipment/views/res_partner_views.xml
Normal file
62
fsm_equipment/views/res_partner_views.xml
Normal 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>
|
||||
Loading…
Reference in a new issue