Files
enterprise-addons/industry_fsm_sale/tests/test_industry_fsm_employee_rate.py

293 lines
15 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details
from odoo import Command
from odoo.tests import tagged
from .common import TestFsmFlowSaleCommon
@tagged('-at_install', 'post_install')
class TestIndustryFsmEmployeeRate(TestFsmFlowSaleCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Add task model with context in variable to facilitate the task creation in this project
cls.Task = cls.env['project.task'].with_context({
'mail_create_nolog': True,
'default_project_id': cls.fsm_project_employee_rate.id,
'default_user_ids': cls.project_user,
})
def test_fsm_employee_rate(self):
""" Test the employee rate as pricing type in fsm project
Test Case:
=========
1) Create task with timesheets containing some employees in employee mappings.
2) Validate the task and check if the SOL in each timesheet is correct with the correct product.
3) Create task with a timesheet containing no employee in employee mappings.
4) Validate the task and check if the SOL in each timesheet is the one in the task with the default product defined in the project.
5) Create task with timesheets with only the employees defined in the mapping.
6) Validate the task and check if the SOL in the task contains the product in the first mapping found based on the timesheets.
"""
self.assertTrue(self.fsm_project_employee_rate.is_fsm, 'The project should be a fsm project.')
self.assertEqual(self.fsm_project_employee_rate.pricing_type, 'employee_rate', 'The pricing of this fsm project should be employee rate since there are some employee mappings into it.')
self.assertEqual(len(self.fsm_project_employee_rate.sale_line_employee_ids), 3, 'The number of employee mappings in this fsm project should be equal to 3 mappings.')
# 1) Create task with timesheets containing some employees in employee mappings.
task = self.Task.create({
'name': 'Fsm Task',
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_user.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
Command.create({
'name': '/',
'employee_id': self.employee_user2.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
Command.create({
'name': '/',
'employee_id': self.employee_manager.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
self.assertEqual(len(task.timesheet_ids), 3, 'The task should have 3 timesheets.')
self.assertFalse(task.sale_line_id, 'The task should have no SOL.')
self.consu_product_ordered.with_user(self.project_user).with_context({'fsm_task_id': task.id}).set_fsm_quantity(1.0)
task.sale_order_id.write({
'order_line': [
Command.create({
'product_id': self.service_timesheet.id,
'product_uom_qty': 2.0,
'name': '/',
}),
]
})
if task.sale_order_id.state != 'sale':
task.sale_order_id.action_confirm()
self.assertEqual(len(task.sale_order_id.order_line), 2)
service_timesheet_order_line = task.sale_order_id.order_line.filtered(lambda order_line: order_line.product_id == self.service_timesheet)
task.write({
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_manager.id,
'unit_amount': 1.0,
'so_line': service_timesheet_order_line.id,
'is_so_line_edited': True,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
self.assertEqual(len(task.timesheet_ids), 4)
# 2) Validate the task and check if the SOL in each timesheet is correct with the correct product.
task.action_fsm_validate()
self.assertEqual(len(task.timesheet_ids.so_line), 4, 'Each timesheet should have a different SOL.')
self.assertEqual(task.sale_order_id.order_line.mapped('qty_delivered'), [1.0] * 5, 'The generated SO should have 4 SOLs in which the quantity delivered should be equal to 1 hour.')
self.assertEqual(task.sale_line_id.product_id, self.fsm_project_employee_rate.timesheet_product_id, 'The SOL linked to the task should have the default service product of the product.')
# 3) Create task with a timesheet containing no employee in employee mappings.
task = self.Task.create({
'name': 'Fsm Task',
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_manager.id,
'unit_amount': 2.0,
'project_id': self.fsm_project_employee_rate.id,
})
]
})
self.assertEqual(len(task.timesheet_ids), 1, 'The task should have 1 timesheet.')
self.assertFalse(task.sale_line_id, 'The task should have no SOL.')
# 4) Validate the task and check if the SOL in each timesheet is the one in the task with the default product defined in the project.
task.action_fsm_validate()
self.assertEqual(task.sale_line_id, task.timesheet_ids.so_line, 'The SOL in task and timesheet should be the same.')
self.assertEqual(task.sale_line_id.product_id, self.fsm_project_employee_rate.timesheet_product_id, 'The product in the SOL should be the default service product defined in the project.')
# 5) Create task with timesheets with only the employees defined in the mapping.
task = self.Task.create({
'name': 'Fsm Task',
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_user3.id,
'unit_amount': 2.0,
'project_id': self.fsm_project_employee_rate.id,
}),
Command.create({
'name': '/',
'employee_id': self.employee_user2.id,
'unit_amount': 2.0,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
self.assertEqual(len(task.timesheet_ids), 2, 'The task should have 2 timesheets.')
self.assertFalse(task.sale_line_id, 'The task should have no SOL.')
# 6) Validate the task and check if the SOL in the task contains the product in the first mapping found based on the timesheets.
task.action_fsm_validate()
# Search the first mapping based on the timesheets in the task
first_employee_mapping = \
self.fsm_project_employee_rate.sale_line_employee_ids\
.filtered(
lambda mapping:
mapping.employee_id in task.timesheet_ids.employee_id
)[:1]
self.assertEqual(task.sale_line_id.product_id, first_employee_mapping.timesheet_product_id, 'The product choose for the SOL in the task should be the product in the first mapping found based on the timesheets in the task.')
self.assertEqual(first_employee_mapping.employee_id, self.employee_user2, 'The mapping found should be the one for the Employee User 2.')
self.assertEqual(first_employee_mapping.timesheet_product_id, self.product_delivery_timesheet1, 'The product in this mapping should be the one defined the Employee User 2.')
self.assertEqual(task.sale_order_id.order_line.mapped('qty_delivered'), [2.0] * 2, 'Each SOL generated should have 2 hours as quantity delivered.')
def test_fsm_employee_rate_with_same_product_in_two_mappings(self):
""" Test when a same service product is in 2 employee mappings for fsm project.
Test Case:
=========
1) Update the employee mappings in the fsm project to have 2 mappings for the same service product.
2) Create task with timesheets containing the mappings with the same product
3) Validate the task and check if the SO generated contains 2 SOLs for the same product but with a different price unit.
"""
self.fsm_project_employee_rate.sale_line_employee_ids.unlink()
ProjectSaleLineEmployeeMap = self.env['project.sale.line.employee.map'].with_context(default_project_id=self.fsm_project_employee_rate.id)
employee_manager_mapping = ProjectSaleLineEmployeeMap.create({
'employee_id': self.employee_manager.id,
'timesheet_product_id': self.product_order_timesheet1.id,
})
employee_user2_mapping = ProjectSaleLineEmployeeMap.create({
'employee_id': self.employee_user2.id,
'timesheet_product_id': self.product_order_timesheet1.id,
})
ProjectSaleLineEmployeeMap.create({
'employee_id': self.employee_user3.id,
'timesheet_product_id': self.product_delivery_timesheet2.id,
})
self.fsm_project_employee_rate.sale_line_employee_ids._compute_price_unit()
employee_manager_mapping.write({'price_unit': 20.0})
self.assertEqual(len(self.fsm_project_employee_rate.sale_line_employee_ids), 3)
self.assertEqual(employee_manager_mapping.timesheet_product_id, employee_user2_mapping.timesheet_product_id, 'Both mappings should have the same service product.')
self.assertNotEqual(employee_manager_mapping.price_unit, employee_user2_mapping.price_unit, 'The price unit of both mappings with the same service product should be different.')
# 2) Create task with timesheets containing the mappings with the same product
task = self.Task.create({
'name': 'Fsm Task',
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_manager.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
Command.create({
'name': '/',
'employee_id': self.employee_user2.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
self.assertEqual(len(task.timesheet_ids), 2, 'The task should have 2 timesheets.')
# 3) Validate the task and check if the SO generated contains 2 SOLs for the same product but with a different price unit.
task.action_fsm_validate()
so = task.sale_order_id
self.assertEqual(len(so.order_line), 2, 'The generated SO should have 2 SOLs.')
self.assertEqual(so.order_line.product_id, self.product_order_timesheet1, 'The both SOLs of this generated SO should have the same service product.')
self.assertNotEqual(so.order_line[0].price_unit, so.order_line[1].price_unit, 'The only different in the both SOLs is the price unit.')
def test_fsm_employee_rate_fpos(self):
""" Test fiscal position applied correctly on employee mappings unit price """
fpos_incl_excl = self.env['account.fiscal.position'].create({
'name': "incl -> excl",
'sequence': 3,
})
tax_include_src, tax_exclude_dst = self.env['account.tax'].create([{
'name': "Include 10%",
'amount': 10.00,
'amount_type': 'percent',
'price_include_override': 'tax_included',
}, {
'name': "Exclude 10%",
'amount': 10.00,
'amount_type': 'percent',
'price_include_override': 'tax_excluded',
'fiscal_position_ids': fpos_incl_excl,
}])
tax_exclude_dst.original_tax_ids = tax_include_src
partner = self.env['res.partner'].create({
'name': "George",
'property_account_position_id': fpos_incl_excl.id,
})
self.product_order_timesheet1.taxes_id = tax_include_src
self.fsm_project_employee_rate.sale_line_employee_ids.unlink()
self.env['project.sale.line.employee.map'].with_context(default_project_id=self.fsm_project_employee_rate.id).create({
'employee_id': self.employee_manager.id,
'timesheet_product_id': self.product_order_timesheet1.id,
'price_unit': 20.0,
})
task = self.Task.create({
'name': 'Fsm Task',
'partner_id': partner.id,
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_manager.id,
'unit_amount': 1.0,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
task.action_fsm_validate()
so = task.sale_order_id
self.assertAlmostEqual(so.order_line.price_unit, 18.18, 2)
def test_fsm_employee_with_duplicate_sol_same_product_same_price(self):
""" Test when sale order has duplicate lines with same product and same price."""
sale_order = self.env['sale.order'].create({
'partner_id': self.partner_1.id,
'order_line': [
Command.create({'product_id': self.product_order_timesheet1.id, 'product_uom_qty': 1.0}),
Command.create({'product_id': self.product_order_timesheet1.id, 'product_uom_qty': 1.0})
]
})
sale_order.action_confirm()
task = self.Task.create({
'name': 'Fsm Task',
'sale_order_id': sale_order.id,
'sale_line_id': sale_order.order_line[1].id,
'timesheet_ids': [
Command.create({
'name': '/',
'employee_id': self.employee_user.id,
'unit_amount': 2.0,
'project_id': self.fsm_project_employee_rate.id,
}),
]
})
# Validate task
task.action_fsm_validate()
self.assertTrue(task.timesheet_ids.so_line, 'Timesheet should be linked to a sale order line')
# the first SOL of the matching product and employee is linked as it was set on the so_line on the timesheet.
# which we have to take on priority
self.assertEqual(task.timesheet_ids.so_line, sale_order.order_line[0])