bemade_fsm: major refactoring of tests in progress (broken).

This commit is contained in:
Marc Durepos 2023-07-13 21:42:16 -04:00
parent 2404c7afb2
commit 1e050584a5
10 changed files with 182 additions and 153 deletions

View file

@ -41,7 +41,7 @@ class Equipment(models.Model):
partner_id = fields.Many2one('res.partner',
string="Owner",
compute="_compute_partner",
search="_search_partner",)
search="_search_partner", )
description = fields.Text(string="Description",
tracking=True)
@ -53,9 +53,11 @@ class Equipment(models.Model):
location_notes = fields.Text(string="Physical Location Notes",
tracking=True)
task_ids = fields.One2many(comodel_name='project.task',
inverse_name='equipment_id',
string='Interventions')
task_ids = fields.Many2many(comodel_name='project.task',
relation="bemade_fsm_task_equipment_rel",
column1="equipment_id",
column2="task_id",
string='Interventions')
@api.depends('partner_location_id')
def _compute_partner(self):

View file

@ -114,7 +114,7 @@ class SaleOrderLine(models.Model):
vals['user_ids'] = template.assignees.ids
vals['tag_ids'] = template.tags.ids
vals['planned_hours'] = template.planned_hours
vals['equipment_id'] = template.equipment_id.id
vals['equipment_ids'] = [Command.set([template.equipment_id.id])]
return vals
tmpl = self.product_id.task_template_id
@ -128,8 +128,8 @@ class SaleOrderLine(models.Model):
"This task has been created from: <a href=# data-oe-model=sale.order data-oe-id=%d>%s</a> (%s)") % (
self.order_id.id, self.order_id.name, self.product_id.name)
task.message_post(body=task_msg)
if not task.equipment_id:
task.equipment_id = self.order_id.equipment_id
if not task.equipment_ids:
task.write({'equipment_ids': [Command.set(self.order_id.equipment_id)]})
task.name = _generate_task_name(tmpl)
return task

View file

@ -5,7 +5,12 @@ from odoo.exceptions import ValidationError
class Task(models.Model):
_inherit = "project.task"
equipment_id = fields.Many2one("bemade_fsm.equipment", string="Equipment to Service", tracking=True)
equipment_ids = fields.Many2many(comodel_name="bemade_fsm.equipment",
relation="bemade_fsm_task_equipment_rel",
column1="task_id",
column2="equipment_id",
string="Equipment to Service",
tracking=True,)
work_order_contacts = fields.Many2many(comodel_name="res.partner",
relation="task_work_order_contact_rel",

View file

@ -3,11 +3,17 @@ from odoo import Command
@tagged("-at_install", "post_install")
class FSMManagerUserTransactionCase(TransactionCase):
class BemadeFSMBaseTest(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user = cls._generate_project_manager_user('Project Manager', 'misterpm')
cls.user_limited = cls._generate_project_user('Project User', 'mruser')
cls.env.ref("industry_fsm.fsm_project").write({'allow_subtasks': True})
@classmethod
def _generate_project_manager_user(cls, name, login):
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')
@ -26,24 +32,117 @@ class FSMManagerUserTransactionCase(TransactionCase):
user_group_sales_manager.id, ]
if user_product_customer:
group_ids.append(user_product_customer.id)
# 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': [Command.set(group_ids)],
})
group_ids.remove(user_group_fsm_manager.id)
group_ids.remove(user_group_project_manager.id)
cls.user_limited = Users.create({
'name': 'Project User',
'login': 'mruser',
'password': 'mruser',
'email': 'mruser@testco.com',
'signature': 'Mr. User',
return cls.env['res.users'].with_context({'no_reset_password': True}).create({
'name': name,
'login': login,
'password': login,
'email': f"{login}@test.co",
'groups_id': [Command.set(group_ids)]
})
@classmethod
def _generate_project_user(cls, name, login):
user = cls._generate_project_manager_user(name, login)
user.write({'groups_id': [Command.unlink(cls.env.ref('project.group_project_manager'))]})
user.write({'groups_id': [Command.unlink(cls.env.ref('industry_fsm.group_fsm_manager'))]})
@classmethod
def _generate_partner(cls, name: str = 'Test Company', company_type: str = 'company', parent=None):
""" 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."""
return cls.env['res.partner'].create({
'name': name,
'company_type': company_type,
'street': '123 Street St.',
'city': 'Montreal',
'state_id': cls.env.ref('base.state_ca_qc').id,
'country_id': cls.env.ref('base.ca').id,
'parent_id': parent and parent.id,
})
@classmethod
def _generate_sale_order(cls, partner, client_order_ref='Test Order', equipment=None):
return cls.env['sale.order'].create({
'partner_id': partner.id,
'client_order_ref': client_order_ref,
'equipment_id': equipment.id,
})
@classmethod
def _generate_sale_order_line(cls, sale_order, product, project, qty=1.0, uom=None, price=100.0, tax_id=False):
return cls.env['sale.order.line'].create({
'order_id': sale_order.id,
'product_id': product.id,
'product_uom_qty': qty,
'product_uom': uom or cls.env.ref("uom.product_uom_hour"),
'price_unit': price,
'tax_id': tax_id,
})
@classmethod
def _generate_equipment(cls, name='test equipment', partner=None):
return cls.env['bemade_fsm.equipment'].create({
'name': name,
'partner_location_id': partner and partner.id,
})
@classmethod
def _generate_product(cls, name='Test Product', product_type='service', service_tracking='task_global_project',
project=None, task_template=None, service_policy='delivered_manual', uom=None):
if 'project' in service_tracking and not project:
project = cls.env.ref("industry_fsm.fsm_project")
uom_id = uom and uom.id or cls.env.ref("uom.product_uom_hour").id
return cls.env['product.product'].create({
'name': name,
'type': product_type,
'service_tracking': service_tracking,
'project_id': service_tracking in ('task_global_project', 'project_only') and project.id,
'project_template_id': service_tracking == 'task_in_project' and project.id,
'task_template_id': task_template and task_template.id,
'service_policy': service_policy,
'uom_id': uom_id,
'uom_po_id': uom_id,
})
@classmethod
def _generate_fsm_project(cls, name='Test Project'):
return cls.env['project.project'].create({
'name': name,
'allow_material': True,
'allow_timesheets': True,
'allow_subtasks': True,
'allow_quotations': True,
'allow_worksheets': True,
'is_fsm': True,
})
@classmethod
def _generate_task_template(cls, parent=None, structure=[], names=['Test Task Template']):
""" Generates a task template with the specified structure and naming.
: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.
: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 len(structure) != len(names) - 1:
raise ValueError("The length of the structure argument must contain exactly one element less than the "
"names argument.")
name = names.pop(0)
template = cls.env['project.task.template'].create({
'name': name,
'parent': parent and parent.id,
})
parent = template
while structure:
subtasks = []
for i in range(0, structure[0]):
subtasks.append(cls.env['project.task.template'].create({
'parent': parent.id,
'name': names[0] + f" {i}",
}))
structure.pop(0)
names.pop(0)
parent = subtasks[0]
return template

View file

@ -1,53 +1,34 @@
from odoo.tests.common import HttpCase, tagged
from .test_bemade_fsm_common import FSMManagerUserTransactionCase
from .test_bemade_fsm_common import BemadeFSMBaseTest
from odoo import Command
from odoo.exceptions import MissingError
@tagged("-at_install", "post_install")
class TestEquipmentCommon(FSMManagerUserTransactionCase):
class TestEquipment(BemadeFSMBaseTest):
def test_crud(self):
self.partner_company = self._generate_partner()
self.partner_contact = self._generate_partner('Site Contact', 'person', self.partner_company)
self.equipment = self._generate_equipment('Test Equipment 1', self.partner_company)
@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%')]).id,
'country_id': cls.env['res.country'].search([('name', '=', 'Canada')]).id
})
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',
'partner_location_id': cls.partner_company.id,
})
@tagged('-at_install', 'post_install')
class TestEquipmentBase(TestEquipmentCommon):
def test_crd(self):
# Just make sure the basic ORM stuff is OK
self.assertTrue(self.equipment in self.partner_company.equipment_ids)
self.assertTrue(len(self.partner_company.equipment_ids) == 1)
self.partner_company.write({'equipment_ids': [Command.set([])]})
# Delete should cascade
self.partner_company.write({'equipment_ids': [Command.set([])]})
with self.assertRaises(MissingError):
self.equipment.name
@tagged('-at_install', 'post_install', 'slow')
class TestEquipmentTours(HttpCase, TestEquipmentCommon):
class TestEquipmentTours(HttpCase, BemadeFSMBaseTest):
@classmethod
def setUpClass(cls):
cls._generate_partner()
cls._generate_partner('Site Contact', 'person', cls.partner_company)
cls._generate_equipment('Test Equipment 1', cls.partner_company)
def test_equipment_base_tour(self):
self.start_tour('/web', 'equipment_base_tour',

View file

@ -1,6 +1,6 @@
from odoo.tests import TransactionCase, HttpCase, tagged, Form
from odoo import Command
from .test_bemade_fsm_common import FSMManagerUserTransactionCase
from .test_bemade_fsm_common import BemadeFSMBaseTest
def create_base_contacts(cls):
@ -22,7 +22,7 @@ def create_base_contacts(cls):
@tagged("-at_install", "post_install")
class SaleOrderFSMContactsCase(FSMManagerUserTransactionCase):
class SaleOrderFSMContactsCase(BemadeFSMBaseTest):
@classmethod
def setUpClass(cls):
@ -60,7 +60,7 @@ class SaleOrderFSMContactsCase(FSMManagerUserTransactionCase):
so.work_order_contacts != so.partner_id.work_order_contacts and len(so.partner_id.work_order_contacts) == 2)
class SaleOrderMultiLocationContactsTest(FSMManagerUserTransactionCase):
class SaleOrderMultiLocationContactsTest(BemadeFSMBaseTest):
@classmethod
def setUpClass(cls):
super().setUpClass()

View file

@ -10,20 +10,12 @@ class TestSalesOrder(TestTaskTemplateCommon):
cls.partner = cls.env['res.partner'].create({
'name': 'Test Partner',
})
cls.equipment =cls.env['bemade_fsm.equipment'].create({
'name': 'test equipment',
'partner_location_id': cls.partner.id,
})
cls.so_equipment = cls.env['bemade_fsm.equipment'].create({
'name': 'test equipment 2',
'partner_location_id': cls.partner.id,
})
cls.sale_order1 = cls.env['sale.order'].create({
'partner_id': cls.partner.id,
'client_order_ref': 'TEST ORDER 1',
'state': 'draft',
'equipment_id': cls.so_equipment.id,
})
cls.equipment = TestSalesOrder._generate_equipment()
cls.so_equipment = TestSalesOrder._generate_equipment('test equipment 2')
cls.sale_order1 = TestSalesOrder._generate_equipment(partner=cls.partner, client_order_ref='TEST ORDER 1',
equipment=cls.so_equipment)
cls.sol_serv_order = TestSalesOrder._generate_sale_order_line(product, project, )
cls.sol_serv_order = cls.env['sale.order.line'].create({
'name': cls.product_task_global_project.name,
'product_id': cls.product_task_global_project.id,
@ -66,6 +58,7 @@ class TestSalesOrder(TestTaskTemplateCommon):
'tax_id': False,
})
@tagged('-at_install', 'post_install')
def test_order_confirmation_simple_template(self):
""" Confirming the order should create a task in the global project. """
@ -144,4 +137,4 @@ class TestSaleOrderTour(HttpCase, TestSalesOrder):
so.action_confirm()
sol = so.order_line.filtered(lambda l: 'Test Product 3' in l.name)
self.start_tour('/web', 'sale_order_tour', login='misterpm')
self.assertTrue(sol.qty_delivered != 0)
self.assertTrue(sol.qty_delivered != 0)

View file

@ -1,4 +1,4 @@
from .test_bemade_fsm_common import FSMManagerUserTransactionCase
from .test_bemade_fsm_common import BemadeFSMBaseTest
from odoo.tests.common import HttpCase, tagged
from odoo.exceptions import MissingError
from odoo import Command
@ -6,7 +6,7 @@ from psycopg2.errors import ForeignKeyViolation
@tagged("-at_install", "post_install")
class TestTaskTemplateCommon(FSMManagerUserTransactionCase):
class TestTaskTemplateCommon(BemadeFSMBaseTest):
@classmethod
def setUpClass(cls):
@ -19,79 +19,26 @@ class TestTaskTemplateCommon(FSMManagerUserTransactionCase):
})
cls.project = cls.env.ref('industry_fsm.fsm_project')
cls.project.write({'allow_subtasks': True,})
cls.product_task_global_project = cls.env['product.product'].create({
'name': 'Test Product 1',
'type': 'service',
'service_tracking': 'task_global_project',
'project_id': cls.project.id,
'task_template_id': cls.task1.id,
'uom_id': hours_uom.id,
'uom_po_id': hours_uom.id,
'service_policy': 'delivered_manual',
})
cls.project_template = cls.env['project.project'].create({
'name': 'Test Project Template',
'allow_material': True,
'allow_timesheets': True,
'allow_subtasks': True,
'allow_quotations': True,
'allow_worksheets': True,
'is_fsm': True,
})
cls.product_task_in_project = cls.env['product.product'].create({
'name': 'Test Product 2',
'type': 'service',
'service_tracking': 'task_in_project',
'task_template_id': cls.task1.id,
'project_template_id': cls.project_template.id,
'uom_po_id': hours_uom.id,
'uom_id': hours_uom.id,
'service_policy': 'delivered_manual',
})
cls.product_task_global_project = cls._generate_product(name='Test Product 1', task_template=cls.task1)
cls.project_template = cls._generate_fsm_project('Test Project Template')
cls.product_task_in_project = cls._generate_product(name='Test Product 2', project=cls.project_template,
service_tracking='task_in_project', task_template=cls.task1)
# Set up a task template tree with 2 children and 1 grandchild
cls.parent_task = cls.env['project.task.template'].create({
'name': 'Parent Template',
'planned_hours': cls.PLANNED_HOURS,
})
cls.child_task_1 = cls.env['project.task.template'].create({
'name': 'Child Template 1',
'parent': cls.parent_task.id,
})
cls.child_task_2 = cls.env['project.task.template'].create({
'name': 'Child Template 2',
'parent': cls.parent_task.id,
})
cls.parent_task.write({'subtasks': [Command.set([cls.child_task_1.id, cls.child_task_2.id])]})
cls.grandchild_task = cls.env['project.task.template'].create({
'name': 'Grandchild Template',
'parent': cls.child_task_2.id
})
cls.child_task_2.write({'subtasks': [Command.set([cls.grandchild_task.id])]})
cls.parent_task = cls._generate_task_template(structure=[2, 1],
names=['Parent Template', 'Child Template',
'Grandchild Template'])
cls.child_task_1 = cls.parent_task.subtasks[0]
cls.child_task_2 = cls.parent_task.subtasks[1]
cls.grandchild_task = cls.child_task_1.subtasks[0]
# Create products using the task tree we just created
cls.product_task_tree_global_project = cls.env['product.product'].create({
'name': 'Test Product 3',
'type': 'service',
'service_tracking': 'task_global_project',
'project_id': cls.project.id,
'task_template_id': cls.parent_task.id,
'service_policy': 'delivered_manual',
'uom_id': hours_uom.id,
'uom_po_id': hours_uom.id,
})
cls.product_task_tree_in_project = cls.env['product.product'].create({
'name': 'Test Product 2',
'type': 'service',
'service_tracking': 'task_in_project',
'task_template_id': cls.parent_task.id,
'project_template_id': cls.project_template.id,
'uom_po_id': hours_uom.id,
'uom_id': hours_uom.id,
'service_policy': 'delivered_manual',
})
cls.product_task_tree_global_project = cls._generate_product(name='Test Product 3',
task_template=cls.parent_task)
cls.product_task_tree_in_project = cls._generate_product(name="Test Product 2", project=cls.project_template,
service_tracking='task_in_project',
task_template=cls.parent_task)
@tagged('-at_install', 'post_install')
@ -105,7 +52,7 @@ class TestTaskTemplate(TestTaskTemplateCommon):
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
subtask should be deleted."""
self.child_task_2.unlink()
self.child_task_1.unlink()
# Reading deleted child's name field should be impossible
with self.assertRaises(MissingError):
test = self.grandchild_task.name

View file

@ -50,7 +50,7 @@
<field name="name">bemade_fsm.equipment.tree</field>
<field name="model">bemade_fsm.equipment</field>
<field name="arch" type="xml">
<tree string="Equipment">
<tree string="Equipment" editable="bottom">
<field name="pid_tag"/>
<field name="name"/>
<field name="description"/>

View file

@ -8,7 +8,9 @@
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="equipment_id" domain="[('partner_location_id', '=', partner_id)]"/>
<field name="equipment_ids"
domain="[('partner_location_id', '=', partner_id)]"
context="{'tree_view_ref': 'bemade_fsm.equipment_view_tree'}"/>
</xpath>
<xpath expr="//page[@name='extra_info']" position="after">
<page string="Field Service" name="field_service">