bemade_fsm: many upgrades including better calendar view

This commit is contained in:
Marc Durepos 2023-07-27 16:13:05 -04:00
parent f4b8770d5d
commit 31a2cae37c
7 changed files with 84 additions and 26 deletions

View file

@ -13,7 +13,8 @@ class FSMVisit(models.Model):
so_section_id = fields.Many2one(comodel_name="sale.order.line", so_section_id = fields.Many2one(comodel_name="sale.order.line",
string="Sale Order Section", string="Sale Order Section",
help="The section on the sale order that represents the labour and parts for " help="The section on the sale order that represents the labour and parts for "
"this visit") "this visit",
ondelete="cascade")
sale_order_id = fields.Many2one(comodel_name="sale.order", sale_order_id = fields.Many2one(comodel_name="sale.order",
string="Sales Order", string="Sales Order",
required=True) required=True)

View file

@ -73,9 +73,13 @@ class SaleOrderLine(models.Model):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'
valid_equipment_ids = fields.One2many(comodel_name="bemade_fsm.equipment", valid_equipment_ids = fields.One2many(comodel_name="bemade_fsm.equipment",
related="order_id.partner_id.owned_equipment_ids") related="order_id.partner_id.owned_equipment_ids")
visit_id = fields.One2many(comodel_name="bemade_fsm.visit", visit_ids = fields.One2many(comodel_name="bemade_fsm.visit",
inverse_name="so_section_id", inverse_name="so_section_id",)
string="Visit") visit_id = fields.Many2one(comodel_name="bemade_fsm.visit",
compute="_compute_visit_id",
string = "Visit",
ondelete='cascade',
store=True)
is_fully_delivered = fields.Boolean(string="Fully Delivered", is_fully_delivered = fields.Boolean(string="Fully Delivered",
compute="_compute_is_fully_delivered", compute="_compute_is_fully_delivered",
help="Indicates whether a line or all the lines in a section have been" help="Indicates whether a line or all the lines in a section have been"
@ -93,6 +97,11 @@ class SaleOrderLine(models.Model):
compute="_compute_is_field_service", compute="_compute_is_field_service",
store=True) store=True)
@api.depends('visit_ids')
def _compute_visit_id(self):
for rec in self:
rec.visit_id = rec.visit_ids and rec.visit_ids[0]
@api.depends('product_id') @api.depends('product_id')
def _compute_is_field_service(self): def _compute_is_field_service(self):
for rec in self: for rec in self:
@ -201,14 +210,16 @@ class SaleOrderLine(models.Model):
@api.depends('order_id.order_line', 'display_type', 'qty_to_deliver', 'order_id.order_line.qty_to_deliver', @api.depends('order_id.order_line', 'display_type', 'qty_to_deliver', 'order_id.order_line.qty_to_deliver',
'order_id.order_line.display_type') 'order_id.order_line.display_type')
def _compute_is_fully_delivered(self): def _compute_is_fully_delivered(self):
self.is_fully_delivered = self._iterate_items_compute_bool(lambda l: l.qty_to_deliver == 0) for rec in self:
rec.is_fully_delivered = rec._iterate_items_compute_bool(lambda l: l.qty_to_deliver == 0)
@api.depends('is_fully_delivered') @api.depends('is_fully_delivered')
def _compute_is_fully_invoiced(self): def _compute_is_fully_invoiced(self):
if not self.is_fully_delivered: for rec in self:
self.is_fully_delivered_and_invoiced = False if not rec.is_fully_delivered:
return rec.is_fully_delivered_and_invoiced = False
self.is_fully_delivered_and_invoiced = self._iterate_items_compute_bool(lambda l: l.qty_to_invoice == 0) return
rec.is_fully_delivered_and_invoiced = rec._iterate_items_compute_bool(lambda l: l.qty_to_invoice == 0)
def get_section_lines(self): def get_section_lines(self):
""" Returns a RecordSet containing the sale order lines that fall under this section. """ """ Returns a RecordSet containing the sale order lines that fall under this section. """

View file

@ -49,6 +49,13 @@ class Task(models.Model):
visit_id = fields.Many2one(comodel_name='bemade_fsm.visit') visit_id = fields.Many2one(comodel_name='bemade_fsm.visit')
# user_id = fields.Many2one('res.users', compute='_compute_user_id')
#
# @api.depends('user_ids')
# def _compute_user_id(self):
# for rec in self:
# rec.user_id = rec.user_ids and rec.user_ids[0] or 0
def _get_related_planning_slots(self): def _get_related_planning_slots(self):
domain = expression.AND([ domain = expression.AND([
self._get_domain_compute_forecast_hours(), self._get_domain_compute_forecast_hours(),

View file

@ -98,13 +98,7 @@ tour.register('equipment_sale_order_tour', {
content: 'Navigate to the Field Service tab.', content: 'Navigate to the Field Service tab.',
trigger: 'a.nav-link[role="tab"]:contains(Field Service)' trigger: 'a.nav-link[role="tab"]:contains(Field Service)'
}, { }, {
content: 'Click Edit', content: 'Check that the equipment is listed in the tab.',
trigger: 'button.o_form_button_edit',
}, {
content: 'Click the equipment dropdown.',
trigger: '.o_field_widget[name="equipment_id"] input',
}, {
content: 'Check that the equipment is in the dropdown.',
trigger: `li.ui-menu-item > a:contains(${TEST_EQPT1})`, trigger: `li.ui-menu-item > a:contains(${TEST_EQPT1})`,
} }
]); ]);

View file

@ -72,6 +72,16 @@ class FSMVisitTest(BemadeFSMBaseTest):
visit_subtasks = visit_task.child_ids visit_subtasks = visit_task.child_ids
self.assertTrue(visit_subtasks and sol1.task_id in visit_subtasks and sol2.task_id in visit_subtasks) self.assertTrue(visit_subtasks and sol1.task_id in visit_subtasks and sol2.task_id in visit_subtasks)
def test_adding_visit_creates_one_sale_order_line(self):
partner = self._generate_partner()
so = self._generate_sale_order()
self._generate_sale_order_line(sale_order=so)
self._generate_sale_order_line(sale_order=so)
self._generate_visit(sale_order=so)
self.assertEqual(len(so.order_line), 3)
def _invoice_sale_order(self, so): def _invoice_sale_order(self, so):
wiz = self.env['sale.advance.payment.inv'].with_context({'active_ids': [so.id]}).create({}) wiz = self.env['sale.advance.payment.inv'].with_context({'active_ids': [so.id]}).create({})
wiz.create_invoices() wiz.create_invoices()

View file

@ -2,6 +2,7 @@ from .test_bemade_fsm_common import BemadeFSMBaseTest
from odoo.tests.common import HttpCase, tagged, Form from odoo.tests.common import HttpCase, tagged, Form
from odoo.exceptions import MissingError from odoo.exceptions import MissingError
from odoo import Command from odoo import Command
from odoo.tools import mute_logger
from psycopg2.errors import ForeignKeyViolation from psycopg2.errors import ForeignKeyViolation
@ -13,7 +14,8 @@ class TestTaskTemplate(BemadeFSMBaseTest):
task_template = self._generate_task_template(names=['Template 1']) task_template = self._generate_task_template(names=['Template 1'])
product = self._generate_product(name="Test Product 1", task_template=task_template) product = self._generate_product(name="Test Product 1", task_template=task_template)
with self.assertRaises(ForeignKeyViolation): with self.assertRaises(ForeignKeyViolation):
task_template.unlink() with mute_logger('odoo.sql_db'):
task_template.unlink()
def test_delete_subtask_template(self): def test_delete_subtask_template(self):
""" Deletion of a child task should be OK even if the parent is on a product. Children of the deleted """ Deletion of a child task should be OK even if the parent is on a product. Children of the deleted

View file

@ -22,11 +22,13 @@
</group> </group>
</page> </page>
</xpath> </xpath>
<button name="action_fsm_validate" class='btn-primary' position="attributes"> <button name="action_fsm_validate" class='btn-primary'
position="attributes">
<attribute name="string">Mark as Delivered</attribute> <attribute name="string">Mark as Delivered</attribute>
<attribute name="groups">industry_fsm.group_fsm_manager</attribute> <attribute name="groups">industry_fsm.group_fsm_manager</attribute>
</button> </button>
<button name="action_fsm_validate" class='btn-secondary' position="attributes"> <button name="action_fsm_validate" class='btn-secondary'
position="attributes">
<attribute name="string">Mark as Delivered</attribute> <attribute name="string">Mark as Delivered</attribute>
<attribute name="groups">industry_fsm.group_fsm_manager</attribute> <attribute name="groups">industry_fsm.group_fsm_manager</attribute>
</button> </button>
@ -39,48 +41,79 @@
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm.project_task_action_fsm_map" model="ir.actions.act_window"> <record id="industry_fsm.project_task_action_fsm_map"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm.project_task_action_to_schedule_fsm" model="ir.actions.act_window"> <record id="industry_fsm.project_task_action_to_schedule_fsm"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm.project_task_action_all_fsm" model="ir.actions.act_window"> <record id="industry_fsm.project_task_action_all_fsm"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm_sale.project_task_action_to_invoice_fsm" model="ir.actions.act_window"> <record id="industry_fsm_sale.project_task_action_to_invoice_fsm"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<!-- Add parent_id = false to domain for planning actions as well --> <!-- Add parent_id = false to domain for planning actions as well -->
<record id="industry_fsm.project_task_action_fsm_planning_groupby_user" model="ir.actions.act_window"> <record id="industry_fsm.project_task_action_fsm_planning_groupby_user"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm.project_task_action_fsm_planning_groupby_project" model="ir.actions.act_window"> <record id="industry_fsm.project_task_action_fsm_planning_groupby_project"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="industry_fsm_report.project_task_action_fsm_planning_groupby_worksheet" model="ir.actions.act_window"> <record id="industry_fsm_report.project_task_action_fsm_planning_groupby_worksheet"
model="ir.actions.act_window">
<field name="domain">[('is_fsm', '=', True), <field name="domain">[('is_fsm', '=', True),
('display_project_id', '!=', False), ('display_project_id', '!=', False),
('parent_id', '=', False)] ('parent_id', '=', False)]
</field> </field>
</record> </record>
<record id="project_task_view_calendar_fsm" model="ir.ui.view">
<field name="name">bemade_fsm.project_task_view_calendar_fsm</field>
<field name="inherit_id" ref="industry_fsm.project_task_view_calendar_fsm"/>
<field name="model">project.task</field>
<field name="arch" type="xml">
<field name="user_ids" position="attributes">
<attribute name="filters">1</attribute>
<attribute name="color">user_ids</attribute>
</field>
</field>
</record>
<record id="project_task_view_calendar_fsm_no_worksheet" model="ir.ui.view">
<field name="name">bemade_fsm.project_task_view_calendar_no_worksheet</field>
<field name="inherit_id"
ref="industry_fsm_report.project_task_view_calendar_fsm_worksheet"/>
<field name="model">project.task</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='worksheet_template_id']"
position="replace"></xpath>
<xpath expr="//calendar" position="attributes">
<attribute name="color">user_ids</attribute>
</xpath>
</field>
</record>
</data> </data>
</odoo> </odoo>