mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 12:12:02 +02:00
19.0 vanilla
This commit is contained in:
parent
79f83631d5
commit
73afc09215
6267 changed files with 1534193 additions and 1130106 deletions
|
|
@ -2,16 +2,16 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo.addons.sale_timesheet.tests.common import TestCommonSaleTimesheet
|
||||
from odoo.fields import Command
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import Form
|
||||
from odoo.tests import Form, tagged
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestProjectBilling(TestCommonSaleTimesheet):
|
||||
""" This test suite provide checks for miscellaneous small things. """
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# set up
|
||||
cls.employee_tde = cls.env['hr.employee'].create({
|
||||
|
|
@ -27,8 +27,8 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
})
|
||||
|
||||
# Sale Order 1, no project/task created, used to timesheet at employee rate
|
||||
SaleOrder = cls.env['sale.order'].with_context(tracking_disable=True)
|
||||
SaleOrderLine = cls.env['sale.order.line'].with_context(tracking_disable=True)
|
||||
SaleOrder = cls.env['sale.order']
|
||||
SaleOrderLine = cls.env['sale.order.line']
|
||||
cls.sale_order_1 = SaleOrder.create({
|
||||
'partner_id': cls.partner_a.id,
|
||||
'partner_invoice_id': cls.partner_a.id,
|
||||
|
|
@ -88,149 +88,17 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
'sale_line_id': cls.so1_line_deliver_no_task.id,
|
||||
'employee_id': cls.employee_user.id,
|
||||
})
|
||||
|
||||
cls.project_task_rate = cls.env['project.project'].search([('sale_line_id', '=', cls.so2_line_deliver_project_task.id)], limit=1)
|
||||
cls.project_task_rate2 = cls.env['project.project'].search([('sale_line_id', '=', cls.so2_line_deliver_project_template.id)], limit=1)
|
||||
|
||||
def test_make_billable_at_task_rate(self):
|
||||
""" Starting from a non billable project, make it billable at task rate """
|
||||
Timesheet = self.env['account.analytic.line']
|
||||
Task = self.env['project.task']
|
||||
# set a customer on the project
|
||||
self.project_non_billable.write({
|
||||
'partner_id': self.partner_2.id,
|
||||
'timesheet_product_id': self.product_delivery_timesheet3,
|
||||
})
|
||||
# create a task and 2 timesheets
|
||||
task = Task.with_context(default_project_id=self.project_non_billable.id).create({
|
||||
'name': 'first task',
|
||||
'partner_id': self.project_non_billable.partner_id.id,
|
||||
'planned_hours': 10,
|
||||
})
|
||||
timesheet1 = Timesheet.create({
|
||||
'name': 'Test Line',
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': 3,
|
||||
'employee_id': self.employee_manager.id,
|
||||
})
|
||||
timesheet2 = Timesheet.create({
|
||||
'name': 'Test Line tde',
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': 2,
|
||||
'employee_id': self.employee_tde.id,
|
||||
})
|
||||
|
||||
# Change project to billable at task rate
|
||||
self.project_non_billable.write({
|
||||
'allow_billable': True,
|
||||
})
|
||||
|
||||
# create wizard
|
||||
wizard = self.env['project.create.sale.order'].with_context(active_id=self.project_non_billable.id, active_model='project.project').create({
|
||||
'line_ids': [
|
||||
Command.create({'product_id': self.product_delivery_timesheet3.id, 'price_unit': self.product_delivery_timesheet3.lst_price}),
|
||||
],
|
||||
})
|
||||
|
||||
self.assertEqual(wizard.partner_id, self.project_non_billable.partner_id, "The wizard should have the same partner as the project")
|
||||
self.assertEqual(len(wizard.line_ids), 1, "The wizard should have one line")
|
||||
self.assertEqual(wizard.line_ids.product_id, self.product_delivery_timesheet3, "The wizard should have one line with right product")
|
||||
|
||||
# create the SO from the project
|
||||
action = wizard.action_create_sale_order()
|
||||
sale_order = self.env['sale.order'].browse(action['res_id'])
|
||||
|
||||
self.assertEqual(sale_order.partner_id, self.project_non_billable.partner_id, "The customer of the SO should be the same as the project")
|
||||
self.assertEqual(len(sale_order.order_line), 1, "The SO should have 1 line")
|
||||
self.assertEqual(sale_order.order_line.product_id, wizard.line_ids.product_id, "The product of the only SOL should be the selected on the wizard")
|
||||
self.assertEqual(sale_order.order_line.project_id, self.project_non_billable, "SOL should be linked to the project")
|
||||
self.assertTrue(sale_order.order_line.task_id, "The SOL creates a task as they were no task already present in the project (system limitation)")
|
||||
self.assertEqual(sale_order.order_line.task_id.project_id, self.project_non_billable, "The created task should be in the project")
|
||||
self.assertEqual(sale_order.order_line.qty_delivered, timesheet1.unit_amount + timesheet2.unit_amount, "The create SOL should have an delivered quantity equals to the sum of tasks'timesheets")
|
||||
self.assertEqual(self.project_non_billable.pricing_type, 'fixed_rate', 'The pricing type of the project should be project rate since we linked a SO in the project.')
|
||||
|
||||
def test_make_billable_at_employee_rate(self):
|
||||
""" Starting from a non billable project, make it billable at employee rate """
|
||||
Timesheet = self.env['account.analytic.line']
|
||||
Task = self.env['project.task']
|
||||
# set a customer on the project
|
||||
self.project_non_billable.write({
|
||||
'partner_id': self.partner_2.id
|
||||
})
|
||||
# create a task and 2 timesheets
|
||||
task = Task.with_context(default_project_id=self.project_non_billable.id).create({
|
||||
'name': 'first task',
|
||||
'partner_id': self.project_non_billable.partner_id.id,
|
||||
'planned_hours': 10,
|
||||
})
|
||||
timesheet1 = Timesheet.create({
|
||||
'name': 'Test Line',
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': 3,
|
||||
'employee_id': self.employee_manager.id,
|
||||
})
|
||||
timesheet2 = Timesheet.create({
|
||||
'name': 'Test Line tde',
|
||||
'project_id': task.project_id.id,
|
||||
'task_id': task.id,
|
||||
'unit_amount': 2,
|
||||
'employee_id': self.employee_user.id,
|
||||
})
|
||||
|
||||
# Change project to billable at employee rate
|
||||
self.project_non_billable.write({
|
||||
'allow_billable': True,
|
||||
})
|
||||
|
||||
# create wizard
|
||||
wizard = self.env['project.create.sale.order'].with_context(active_id=self.project_non_billable.id, active_model='project.project').create({
|
||||
'partner_id': self.partner_2.id,
|
||||
'line_ids': [
|
||||
(0, 0, {'product_id': self.product_delivery_timesheet1.id, 'price_unit': 15, 'employee_id': self.employee_tde.id}), # product creates no T
|
||||
(0, 0, {'product_id': self.product_delivery_timesheet1.id, 'price_unit': 15, 'employee_id': self.employee_manager.id}), # product creates no T (same product than previous one)
|
||||
(0, 0, {'product_id': self.product_delivery_timesheet3.id, 'price_unit': self.product_delivery_timesheet3.list_price, 'employee_id': self.employee_user.id}), # product creates new T in new P
|
||||
]
|
||||
})
|
||||
|
||||
self.assertEqual(wizard.partner_id, self.project_non_billable.partner_id, "The wizard should have the same partner as the project")
|
||||
self.assertEqual(wizard.project_id, self.project_non_billable, "The wizard'project should be the non billable project")
|
||||
|
||||
# create the SO from the project
|
||||
action = wizard.action_create_sale_order()
|
||||
sale_order = self.env['sale.order'].browse(action['res_id'])
|
||||
|
||||
self.assertEqual(sale_order.partner_id, self.project_non_billable.partner_id, "The customer of the SO should be the same as the project")
|
||||
self.assertEqual(len(sale_order.order_line), 2, "The SO should have 2 lines, as in wizard map there were 2 time the same product with the same price (for 2 different employees)")
|
||||
self.assertEqual(len(self.project_non_billable.sale_line_employee_ids), 3, "The project have 3 lines in its map")
|
||||
self.assertEqual(self.project_non_billable.pricing_type, 'employee_rate', 'The pricing type of the project should be employee rate since we have some mappings in this project.')
|
||||
self.assertEqual(self.project_non_billable.sale_line_id, sale_order.order_line[0], "The wizard sets sale line fallbakc on project as the first of the list")
|
||||
self.assertEqual(task.sale_line_id, sale_order.order_line[0], "The wizard sets sale line fallback on tasks")
|
||||
self.assertEqual(task.partner_id, wizard.partner_id, "The wizard sets the customer on tasks to make SOL line field visible")
|
||||
|
||||
line1 = sale_order.order_line.filtered(lambda sol: sol.product_id == self.product_delivery_timesheet1)
|
||||
line2 = sale_order.order_line.filtered(lambda sol: sol.product_id == self.product_delivery_timesheet3)
|
||||
|
||||
self.assertTrue(line1, "Sale line 1 with product 1 should exists")
|
||||
self.assertTrue(line2, "Sale line 2 with product 3 should exists")
|
||||
|
||||
self.assertFalse(line1.project_id, "Sale line 1 should be linked to the 'non billable' project")
|
||||
self.assertEqual(line2.project_id, self.project_non_billable, "Sale line 3 should be linked to the 'non billable' project")
|
||||
self.assertEqual(line1.price_unit, 15.0, "The unit price of SOL 1 should be 15.0")
|
||||
self.assertEqual(line1.product_uom_qty, 3, "The ordered qty of SOL 1 should be 3")
|
||||
self.assertEqual(line2.product_uom_qty, 2, "The ordered qty of SOL 2 should be 2")
|
||||
|
||||
self.assertEqual(self.project_non_billable.sale_line_employee_ids.mapped('sale_line_id'), sale_order.order_line, "The SO lines of the map should be the same of the sales order")
|
||||
self.assertEqual(timesheet1.so_line, line1, "Timesheet1 should be linked to sale line 1, as employee manager create the timesheet")
|
||||
self.assertEqual(timesheet2.so_line, line2, "Timesheet2 should be linked to sale line 2, as employee tde create the timesheet")
|
||||
self.assertEqual(timesheet1.unit_amount, line1.qty_delivered, "Sale line 1 should have a delivered qty equals to the sum of its linked timesheets")
|
||||
self.assertEqual(timesheet2.unit_amount, line2.qty_delivered, "Sale line 2 should have a delivered qty equals to the sum of its linked timesheets")
|
||||
cls.project_sale_manager = mail_new_test_user(
|
||||
cls.env,
|
||||
name='Project Manager',
|
||||
login='project_manager',
|
||||
email='project_manager@example.com',
|
||||
groups='project.group_project_manager,sales_team.group_sale_manager',
|
||||
)
|
||||
|
||||
def test_billing_employee_rate(self):
|
||||
""" Check task and subtask creation, and timesheeting in a project billed at 'employee rate'. Then move the task into a 'task rate' project. """
|
||||
Task = self.env['project.task'].with_context(tracking_disable=True)
|
||||
Task = self.env['project.task']
|
||||
Timesheet = self.env['account.analytic.line']
|
||||
|
||||
# create a task
|
||||
|
|
@ -265,14 +133,15 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
self.assertEqual(self.project_employee_rate_manager.project_id, timesheet1.project_id, "The timesheet should be linked to the project of the map entry")
|
||||
|
||||
# create a subtask
|
||||
subtask = Task.with_context(default_project_id=self.project_subtask.id).create({
|
||||
subtask = Task.create({
|
||||
'name': 'first subtask task',
|
||||
'parent_id': task.id,
|
||||
'project_id': self.project_subtask.id,
|
||||
})
|
||||
|
||||
self.assertFalse(subtask.allow_billable, "Subtask in non billable project should be non billable too")
|
||||
self.assertFalse(subtask.project_id.allow_billable, "The subtask project is non billable even if the subtask is")
|
||||
self.assertEqual(subtask.partner_id, subtask.parent_id.partner_id, "Subtask should have the same customer as the one from their mother")
|
||||
self.assertFalse(subtask.partner_id, "Subtask in non billable project should not have a customer")
|
||||
|
||||
# log timesheet on subtask
|
||||
timesheet2 = Timesheet.create({
|
||||
|
|
@ -296,12 +165,12 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
self.assertEqual(task.sale_line_id, self.so1_line_deliver_no_task, "The task should keep the same SOL since the partner_id has not changed when the project of the task has changed.")
|
||||
self.assertEqual(task.partner_id, self.partner_a, "Task created in a project billed on 'employee rate' should have the same customer when it has been created.")
|
||||
# the `subtask.sale_line_id` is consider to be recompute,
|
||||
# but the result differ after the write of display_project_id without depend on it
|
||||
# but the result differ after the write of project_id without depend on it
|
||||
task.flush_model(["sale_line_id"])
|
||||
|
||||
# move subtask into task rate project
|
||||
subtask.write({
|
||||
'display_project_id': self.project_task_rate2.id,
|
||||
'project_id': self.project_task_rate2.id,
|
||||
})
|
||||
|
||||
self.assertTrue(subtask.allow_billable, "Subtask should keep the billable type from its parent, even when they are moved into another project")
|
||||
|
|
@ -311,8 +180,9 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
task2 = Task.with_context(default_project_id=self.project_employee_rate.id).create({
|
||||
'name': 'first task',
|
||||
'partner_id': self.partner_a.id,
|
||||
'sale_line_id': False
|
||||
})
|
||||
# This needs to be done after creation because setting partner_id causes _get_last_sol_of_customer to recompute the sale_line_id
|
||||
task2.update({'sale_line_id': False})
|
||||
|
||||
# log timesheet on task in 'employee rate' project without any fallback (no map, no SOL on task, no SOL on project)
|
||||
timesheet3 = Timesheet.create({
|
||||
|
|
@ -341,7 +211,7 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
Check task and subtask creation, and timesheeting in a project billed at 'task rate'.
|
||||
Then move the task into a 'employee rate' project then, 'non billable'.
|
||||
"""
|
||||
Task = self.env['project.task'].with_context(tracking_disable=True)
|
||||
Task = self.env['project.task']
|
||||
Timesheet = self.env['account.analytic.line']
|
||||
|
||||
# create a task
|
||||
|
|
@ -367,20 +237,20 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
subtask = Task.with_context(default_project_id=self.project_task_rate.id).create({
|
||||
'name': 'first subtask task',
|
||||
'parent_id': task.id,
|
||||
'display_project_id': self.project_subtask.id,
|
||||
'project_id': self.project_subtask.id,
|
||||
})
|
||||
|
||||
self.assertEqual(subtask.partner_id, subtask.parent_id.partner_id, "Subtask should have the same customer as the one from their mother")
|
||||
self.assertFalse(subtask.partner_id, "Subtask should not have the customer if it's project is not billable")
|
||||
|
||||
# log timesheet on subtask
|
||||
timesheet2 = Timesheet.create({
|
||||
'name': 'Test Line on subtask',
|
||||
'project_id': subtask.display_project_id.id,
|
||||
'project_id': subtask.project_id.id,
|
||||
'task_id': subtask.id,
|
||||
'unit_amount': 50,
|
||||
'employee_id': self.employee_user.id,
|
||||
})
|
||||
self.assertEqual(subtask.display_project_id, timesheet2.project_id, "The timesheet is in the subtask project")
|
||||
self.assertEqual(subtask.project_id, timesheet2.project_id, "The timesheet is in the subtask project")
|
||||
self.assertFalse(timesheet2.so_line, "The timesheet should not be linked to SOL as it's a non billable project")
|
||||
# the `subtask.sale_line_id` is consider to be recompute,
|
||||
# but the result differ after the write of project_id
|
||||
|
|
@ -391,7 +261,7 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
'project_id': self.project_employee_rate.id,
|
||||
})
|
||||
subtask.write({
|
||||
'display_project_id': self.project_employee_rate.id,
|
||||
'project_id': self.project_employee_rate.id,
|
||||
})
|
||||
|
||||
self.assertEqual(task.sale_line_id, self.project_task_rate.sale_line_id, "Task moved in a employee rate billable project should keep its SOL because the partner_id has not changed too.")
|
||||
|
|
@ -439,15 +309,15 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
3) Create an employee mapping in this project
|
||||
4) Check if the partner_id and pricing_type fields have been changed
|
||||
"""
|
||||
with Form(self.env['project.project'].with_context({'tracking_disable': True})) as project_form:
|
||||
with Form(self.env['project.project'].with_user(self.project_sale_manager)) as project_form:
|
||||
project_form.name = 'Test Billable Project'
|
||||
project_form.allow_billable = True
|
||||
# `sale_line_employee_ids` is not visible if `partner_id` is not set
|
||||
# As the behavior of the test is to check the partner on the project
|
||||
# is set to the partner of the order line, temporary make the field visible
|
||||
# even if it's not the case in the reality, in the web client
|
||||
# {'invisible': ['|', ('allow_billable', '=', False), ('partner_id', '=', False)]}
|
||||
project_form._view['modifiers']['sale_line_employee_ids']['invisible'] = False
|
||||
# not allow_billable or not partner_id
|
||||
project_form._view['modifiers']['sale_line_employee_ids']['invisible'] = 'False'
|
||||
with project_form.sale_line_employee_ids.new() as mapping_form:
|
||||
mapping_form.employee_id = self.employee_manager
|
||||
mapping_form.sale_line_id = self.so.order_line[:1]
|
||||
|
|
@ -463,7 +333,6 @@ class TestProjectBilling(TestCommonSaleTimesheet):
|
|||
this test will manually set the state and payment_status to be in the same condition
|
||||
than the feature "Invoicing Switch Threshold".
|
||||
"""
|
||||
self.sale_order_1.action_confirm()
|
||||
timesheet1 = self.env['account.analytic.line'].create({
|
||||
'name': '/',
|
||||
'project_id': self.project_task_rate.id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue