bemade_fsm: added a test for contact setting on SO shipping address change. Fixes #53.
This commit is contained in:
parent
6f37902f42
commit
eea5b54a4f
8 changed files with 221 additions and 20 deletions
|
|
@ -4,3 +4,4 @@ from . import sale_order
|
|||
from . import equipment
|
||||
from . import task
|
||||
from . import res_partner
|
||||
from . import fsm_visit
|
||||
|
|
|
|||
37
bemade_fsm/models/fsm_visit.py
Normal file
37
bemade_fsm/models/fsm_visit.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class FSMVisit(models.Model):
|
||||
_name = "bemade_fsm.visit"
|
||||
_description = 'Represents a single visit by assigned service personnel.'
|
||||
|
||||
label = fields.Text(string="Label",
|
||||
required=True,
|
||||
related='so_section_id.name',
|
||||
readonly=False)
|
||||
approx_date = fields.Date(string='Approximate Date')
|
||||
so_section_id = fields.Many2one(comodel_name="sale.order.line",
|
||||
string="Sale Order Section",
|
||||
help="The section on the sale order that represents the labour and parts for "
|
||||
"this visit")
|
||||
sale_order_id = fields.Many2one(comodel_name="sale.order",
|
||||
string="Sales Order",
|
||||
required=True)
|
||||
is_completed = fields.Boolean(string="Completed",
|
||||
related="so_section_id.is_fully_delivered")
|
||||
is_invoiced = fields.Boolean(string="Invoiced",
|
||||
compute="_compute_is_invoiced")
|
||||
|
||||
def _compute_is_invoiced(self):
|
||||
self.is_invoiced = False
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
recs = super().create(vals_list)
|
||||
for i, rec in enumerate(recs):
|
||||
rec.so_section_id = rec.env['sale.order.line'].create({
|
||||
'order_id': rec.sale_order_id.id,
|
||||
'display_type': 'line_section',
|
||||
'name': vals_list[i]['label'],
|
||||
})
|
||||
return recs
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
from odoo import fields, models, api, _, Command
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
|
|
@ -24,6 +25,9 @@ class SaleOrder(models.Model):
|
|||
inverse='_inverse_default_contacts',
|
||||
string='Work Order Recipients',
|
||||
store=True)
|
||||
visit_ids = fields.One2many(comodel_name='bemade_fsm.visit',
|
||||
inverse_name="sale_order_id",
|
||||
readonly=False)
|
||||
|
||||
@api.onchange('partner_shipping_id')
|
||||
def _onchange_partner_shipping_id(self):
|
||||
|
|
@ -53,6 +57,12 @@ class SaleOrder(models.Model):
|
|||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
visit_id = fields.One2many(comodel_name="bemade_fsm.visit",
|
||||
inverse_name="so_section_id",
|
||||
string="Visit")
|
||||
is_fully_delivered = fields.Boolean(string="Fully Delivered",
|
||||
compute="_compute_is_fully_delivered")
|
||||
|
||||
def _timesheet_create_task(self, project):
|
||||
""" Generate task for the given so line, and link it.
|
||||
:param project: record of project.project in which the task should be created
|
||||
|
|
@ -78,7 +88,7 @@ class SaleOrderLine(models.Model):
|
|||
task.child_ids.write({'sale_order_id': None, 'sale_line_id': None, })
|
||||
return task
|
||||
|
||||
def _generate_task_name(template = None):
|
||||
def _generate_task_name(template=None):
|
||||
template_name = template and template.name
|
||||
return f"{self.order_id.name}: {self.order_id.partner_shipping_id.name} - {self.name} ({template_name})"
|
||||
|
||||
|
|
@ -116,3 +126,27 @@ class SaleOrderLine(models.Model):
|
|||
task.equipment_id = self.order_id.equipment_id
|
||||
task.name = _generate_task_name(tmpl)
|
||||
return task
|
||||
|
||||
@api.depends('order_id.order_line', 'display_type', 'qty_to_deliver', 'order_id.order_line.qty_to_deliver',
|
||||
'order_id.order_line.display_type')
|
||||
def _compute_is_fully_delivered(self):
|
||||
if not self.display_type:
|
||||
self.is_fully_delivered = self.qty_to_deliver == 0
|
||||
elif self.display_type == 'line_note':
|
||||
self.is_fully_delivered = True
|
||||
else:
|
||||
for line in self.order_id.order_line:
|
||||
# Iterate through the lines on the SO in order until we find this one in the list
|
||||
found = False
|
||||
if line == self:
|
||||
found = True
|
||||
if not found:
|
||||
continue
|
||||
# If we've hit the next section without returning False, all lines in this section were delivered
|
||||
if found and line.display_type == 'line_section':
|
||||
self.is_fully_delivered = True
|
||||
return
|
||||
if line.qty_to_deliver > 0:
|
||||
self.is_fully_delivered = False
|
||||
return
|
||||
self.is_fully_delivered = True
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ access_bemade_fsm_task_template,bemade_fsm_task_template,model_project_task_temp
|
|||
access_bemade_fsm_task_template,bemade_fsm_task_template,model_project_task_template,project.group_project_user,1,1,1,1
|
||||
access_bemade_fsm_equipment,bemade_fsm_equipment,model_bemade_fsm_equipment,base.group_user,1,1,1,1
|
||||
access_bemade_fsm_equipment_tag,bemade_fsm_equipment_tag,model_bemade_fsm_equipment_tag,base.group_user,1,1,1,1
|
||||
access_bemade_fsm_equipment_type,access_bemade_fsm_equipment_type,model_bemade_fsm_equipment_type,base.group_user,1,0,0,0
|
||||
access_bemade_fsm_equipment_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
|
||||
|
|
|
|||
|
|
|
@ -4,3 +4,4 @@ from . import test_sale_order
|
|||
from . import test_equipment
|
||||
from . import test_fsm_contact_setting
|
||||
from . import test_so_task_contacts
|
||||
from . import test_fsm_visit
|
||||
|
|
|
|||
|
|
@ -1,29 +1,33 @@
|
|||
from odoo.tests import TransactionCase, HttpCase, tagged
|
||||
from odoo.tests import TransactionCase, HttpCase, tagged, Form
|
||||
from odoo import Command
|
||||
from .test_bemade_fsm_common import FSMManagerUserTransactionCase
|
||||
|
||||
|
||||
def create_base_contacts(cls):
|
||||
Partner = cls.env['res.partner']
|
||||
cls.parent_co = Partner.create({
|
||||
'name': 'Parent Co',
|
||||
'company_type': 'company',
|
||||
})
|
||||
cls.contact_1 = Partner.create({
|
||||
'name': 'Contact 1',
|
||||
'company_type': 'person',
|
||||
'parent_id': cls.parent_co.id,
|
||||
})
|
||||
cls.contact_2 = Partner.create({
|
||||
'name': 'Contact 2',
|
||||
'company_type': 'person',
|
||||
'parent_id': cls.parent_co.id,
|
||||
})
|
||||
|
||||
|
||||
@tagged("-at_install", "post_install")
|
||||
class SaleOrderFSMContactsCase(FSMManagerUserTransactionCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
Partner = cls.env['res.partner']
|
||||
cls.parent_co = Partner.create({
|
||||
'name': 'Parent Co',
|
||||
'company_type': 'company',
|
||||
})
|
||||
cls.contact_1 = Partner.create({
|
||||
'name': 'Contact 1',
|
||||
'company_type': 'person',
|
||||
'parent_id': cls.parent_co.id,
|
||||
})
|
||||
cls.contact_2 = Partner.create({
|
||||
'name': 'Contact 2',
|
||||
'company_type': 'person',
|
||||
'parent_id': cls.parent_co.id,
|
||||
})
|
||||
create_base_contacts(cls)
|
||||
|
||||
def test_site_contacts(self):
|
||||
# Make sure the SO pulls the defaults from the partner correctly
|
||||
|
|
@ -56,10 +60,11 @@ class SaleOrderFSMContactsCase(FSMManagerUserTransactionCase):
|
|||
so.work_order_contacts != so.partner_id.work_order_contacts and len(so.partner_id.work_order_contacts) == 2)
|
||||
|
||||
|
||||
class SaleOrderMultiLocationContactsTest(SaleOrderFSMContactsCase):
|
||||
class SaleOrderMultiLocationContactsTest(FSMManagerUserTransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
create_base_contacts(cls)
|
||||
cls.shipping_location = cls.env['res.partner'].create({
|
||||
'name': 'Shipping location',
|
||||
'company_type': 'company',
|
||||
|
|
@ -90,3 +95,18 @@ class SaleOrderMultiLocationContactsTest(SaleOrderFSMContactsCase):
|
|||
self.assertEqual(so.partner_shipping_id, self.shipping_location)
|
||||
self.assertEqual(so.site_contacts, self.shipping_location.site_contacts)
|
||||
self.assertEqual(so.work_order_contacts, self.shipping_location.work_order_contacts)
|
||||
|
||||
def test_onchange_shipping_address(self):
|
||||
so = self.env['sale.order'].create({
|
||||
'partner_id': self.parent_co.id,
|
||||
'partner_shipping_id': self.parent_co.id,
|
||||
})
|
||||
self.assertFalse(so.work_order_contacts)
|
||||
self.assertFalse(so.site_contacts)
|
||||
|
||||
form = Form(so)
|
||||
form.partner_shipping_id = self.shipping_location
|
||||
form.save()
|
||||
|
||||
self.assertEqual(so.work_order_contacts, self.shipping_location.work_order_contacts)
|
||||
self.assertEqual(so.site_contacts, self.shipping_location.site_contacts)
|
||||
|
|
|
|||
91
bemade_fsm/tests/test_fsm_visit.py
Normal file
91
bemade_fsm/tests/test_fsm_visit.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
from odoo.tests import TransactionCase, tagged, Form
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class FSMVisitTest(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
def test_create_visit_sets_name_on_section(self):
|
||||
so = self.generate_sale_order()
|
||||
self.add_service_so_line(so)
|
||||
|
||||
visit = self.generate_visit(so)
|
||||
|
||||
self.assertTrue(visit.so_section_id)
|
||||
self.assertEqual(visit.so_section_id.name, visit.label)
|
||||
|
||||
def test_change_visit_section_name(self):
|
||||
so = self.generate_sale_order()
|
||||
visit = self.generate_visit(so, label="First Label")
|
||||
line = visit.so_section_id
|
||||
|
||||
line.name = "Second Label"
|
||||
|
||||
self.assertEqual(visit.label, "Second Label")
|
||||
|
||||
def test_change_visit_label_changes_section_name(self):
|
||||
so = self.generate_sale_order()
|
||||
visit = self.generate_visit(so, label="First Label")
|
||||
line = visit.so_section_id
|
||||
|
||||
visit.label = "Second Label"
|
||||
|
||||
self.assertEqual(line.name, "Second Label")
|
||||
|
||||
def test_visit_completes_when_task_completes(self):
|
||||
so = self.generate_sale_order()
|
||||
visit = self.generate_visit(so)
|
||||
sol = self.add_service_so_line(so, task=True)
|
||||
so.action_confirm()
|
||||
task = so.order_line.filtered(lambda l: l.task_id).task_id
|
||||
|
||||
task.action_fsm_validate()
|
||||
|
||||
self.assertTrue(visit.is_completed)
|
||||
|
||||
def generate_visit(self, sale_order, label="Test Label"):
|
||||
return self.env['bemade_fsm.visit'].create([{
|
||||
'sale_order_id': sale_order.id,
|
||||
'label': label,
|
||||
}])
|
||||
|
||||
def generate_sale_order(self, partner_id=None):
|
||||
so = self.env['sale.order'].create({
|
||||
'partner_id': partner_id or self.generate_partner().id,
|
||||
'client_order_ref': 'Test',
|
||||
})
|
||||
return so
|
||||
|
||||
def add_service_so_line(self, sale_order, task: bool = False):
|
||||
""" Generates a sales order line for a service product.
|
||||
|
||||
:param sale_order: The sales order to which the new line is to be added
|
||||
:param task: If true, the created line will be for a product with service_tracking=task_global_project
|
||||
"""
|
||||
if not task:
|
||||
service_tracking = 'no'
|
||||
project = False
|
||||
else:
|
||||
project = self.env.ref("industry_fsm.fsm_project")
|
||||
service_tracking = 'task_global_project'
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Test Product',
|
||||
'type': 'service',
|
||||
'service_tracking': service_tracking,
|
||||
'project_id': project and project.id,
|
||||
'price': 100.0,
|
||||
'sale_ok': True,
|
||||
})
|
||||
return self.env['sale.order.line'].create({
|
||||
'product_id': product.id,
|
||||
'order_id': sale_order.id,
|
||||
})
|
||||
|
||||
def generate_partner(self):
|
||||
partner = self.env['res.partner'].create({
|
||||
'name': 'Test Partner',
|
||||
'company_type': 'company',
|
||||
})
|
||||
return partner
|
||||
|
|
@ -8,7 +8,11 @@
|
|||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='other_information']" position="before">
|
||||
<page name="field_service" string="Field Service">
|
||||
<group name="field_service_info">
|
||||
<group name="fsm_visits" string="Service Visits">
|
||||
<field name="visit_ids"
|
||||
context="{'tree_view_ref': 'bemade_fsm.bemade_fsm_visit_tree'}"/>
|
||||
</group>
|
||||
<group name="field_service_info" string="Contacts and Equipment">
|
||||
<field name="equipment_id"
|
||||
domain="[('partner_location_id', '=', partner_shipping_id)]"
|
||||
context="{'default_partner_location_id': partner_shipping_id,}"/>
|
||||
|
|
@ -21,5 +25,17 @@
|
|||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<record id="bemade_fsm_visit_tree" model="ir.ui.view">
|
||||
<field name="name">bemade_fsm.visit.tree</field>
|
||||
<field name="model">bemade_fsm.visit</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="label"/>
|
||||
<field name="approx_date"/>
|
||||
<field name="is_completed" widget="boolean"/>
|
||||
<field name="is_invoiced" widget="boolean"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in a new issue