251 lines
11 KiB
Python
251 lines
11 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, Form
|
|
from .common import TestFsmFlowSaleCommon
|
|
|
|
|
|
@tagged('-at_install', 'post_install')
|
|
class TestIndustryFsmTask(TestFsmFlowSaleCommon):
|
|
|
|
def test_partner_id_follows_so_shipping_address(self):
|
|
""" For fsm tasks linked to a sale order, the partner_id should be the same as
|
|
the partner_shipping_id set on the sale sale order.
|
|
"""
|
|
self.env.user.group_ids += self.env.ref('account.group_delivery_invoice_address')
|
|
so = self.env['sale.order'].create([{
|
|
'name': 'Test SO linked to fsm task',
|
|
'partner_id': self.partner_1.id,
|
|
}])
|
|
sol = self.env['sale.order.line'].create([{
|
|
'name': 'Test SOL linked to a fsm tasl',
|
|
'order_id': so.id,
|
|
'task_id': self.task.id,
|
|
'product_id': self.service_product_delivered.id,
|
|
'product_uom_qty': 3,
|
|
}])
|
|
self.task.sale_line_id = sol
|
|
partner_2 = self.env['res.partner'].create({'name': 'A Test Partner 2'})
|
|
|
|
# 1. Modyfing shipping address on SO should update the customer on the task
|
|
self.assertEqual(so.partner_id, self.partner_1)
|
|
self.assertEqual(so.partner_shipping_id, self.partner_1)
|
|
self.assertEqual(self.task.partner_id, self.partner_1)
|
|
|
|
so.partner_shipping_id = partner_2
|
|
|
|
self.assertEqual(so.partner_id, self.partner_1)
|
|
self.assertEqual(so.partner_shipping_id, partner_2)
|
|
self.assertEqual(self.task.partner_id, partner_2,
|
|
"Modifying the shipping partner on a sale order linked to a fsm task should update the partner of this task accordingly")
|
|
|
|
# 2. partner_id should be False for task not billable
|
|
self.task.project_id.allow_billable = False
|
|
so.partner_shipping_id = partner_2
|
|
self.assertFalse(self.task.partner_id, "Partner id should be set to False for non-billable tasks")
|
|
|
|
def test_fsm_task_under_warranty(self):
|
|
""" Ensure that the product price is zero in the sales order line for task is under warranty.
|
|
Test Case:
|
|
=========
|
|
1. Create a task and add timesheet line to it
|
|
2. Set the task under warranty
|
|
3. Validate the task
|
|
4. Check the price unit of the sale order line
|
|
"""
|
|
self.task.write({'under_warranty': True, 'partner_id': self.partner_1.id})
|
|
self.env['account.analytic.line'].create({
|
|
'name': 'Timesheet',
|
|
'task_id': self.task.id,
|
|
'unit_amount': 0.25,
|
|
'date': '2024-04-22',
|
|
'employee_id': self.employee_user2.id,
|
|
})
|
|
self.task.action_fsm_validate()
|
|
self.assertEqual(self.task.sale_line_id.price_unit, 0.0, "If task is under warranty, the price of the sale order line should be 0.0")
|
|
|
|
def test_fsm_task_sale_line_id(self):
|
|
"""Ensure that no Sale Order is generated on task if task is under warranty
|
|
and there are timesheets but no product on the task.
|
|
Test Case:
|
|
=========
|
|
1. Create a task and add timesheet line to it
|
|
2. Set the task under warranty
|
|
3. Validate the task without any product
|
|
4. Sale order should not be generated
|
|
"""
|
|
self.task.write({'under_warranty': True, 'partner_id': self.partner_1.id})
|
|
self.env['account.analytic.line'].create({
|
|
'name': 'Timesheet',
|
|
'task_id': self.task.id,
|
|
'unit_amount': 0.50,
|
|
'date': '2024-07-07',
|
|
'employee_id': self.employee_user2.id,
|
|
})
|
|
self.task.action_fsm_validate()
|
|
self.assertFalse(self.task.sale_order_id, 'Sale order should not be generated on the task.')
|
|
self.assertFalse(self.task.timesheet_ids.so_line, 'The timesheet should not be linked to a SOL.')
|
|
|
|
def test_read_timesheet_product_id_portal_user(self):
|
|
portal_user = self._create_new_portal_user()
|
|
self.task.project_id.write({
|
|
'collaborator_ids': [
|
|
Command.create({'partner_id': portal_user.partner_id.id}),
|
|
],
|
|
})
|
|
self.assertTrue(
|
|
Form(
|
|
self.task.with_user(portal_user),
|
|
view="industry_fsm_sale.project_sharing_project_task_inherit_view_form",
|
|
)
|
|
)
|
|
|
|
def test_under_warranty_copied_when_creating_task_from_template(self):
|
|
template_task = self.env["project.task"].create({
|
|
"name": "Template",
|
|
"project_id": self.fsm_project.id,
|
|
"is_template": True,
|
|
"under_warranty": True,
|
|
"description": "Template description",
|
|
})
|
|
|
|
task_id = template_task.action_create_from_template()
|
|
task = self.env["project.task"].browse(task_id)
|
|
self.assertTrue(task.under_warranty, "The 'under_warranty' is not copied from the template task.")
|
|
|
|
def test_under_warranty_copied_when_creating_project_from_project_template(self):
|
|
fsm_project = self.env['project.project'].create({
|
|
'name': 'Field Service',
|
|
'is_fsm': True,
|
|
'allow_billable': True,
|
|
'allow_timesheets': True,
|
|
'is_template': True,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
self.env["project.task"].create({
|
|
'name': 'Template',
|
|
'project_id': fsm_project.id,
|
|
'is_template': True,
|
|
'under_warranty': True,
|
|
'description': 'Template description',
|
|
})
|
|
|
|
project_id = fsm_project.action_create_from_template()
|
|
self.assertTrue(project_id.task_ids.under_warranty, "The 'under_warranty' is not copied from the template task.")
|
|
|
|
def test_fsm_task_timesheet_uses_customer_pricelist(self):
|
|
"""Test that the timesheet service line uses the fixed price from the customer's assigned pricelist.
|
|
|
|
Steps to reproduce:
|
|
- Create a fixed-price pricelist that applies to all products.
|
|
- Assign the pricelist to the customer.
|
|
- Create a task linked to that customer.
|
|
- Add a timesheet entry to the task.
|
|
- Mark the task as done.
|
|
- Verify that the price of the timesheet service line in the sale order matches the fixed price from the pricelist.
|
|
"""
|
|
pricelist = self.env['product.pricelist'].create({
|
|
'name': 'Price List',
|
|
'currency_id': self.env.company.currency_id.id,
|
|
'item_ids': [Command.create({
|
|
'applied_on': '3_global',
|
|
'compute_price': 'fixed',
|
|
'fixed_price': 0.0,
|
|
})],
|
|
})
|
|
|
|
self.partner.property_product_pricelist = pricelist
|
|
self.task.partner_id = self.partner
|
|
self.env['account.analytic.line'].create({
|
|
'employee_id': self.employee_user2.id,
|
|
'task_id': self.task.id,
|
|
'unit_amount': 2.0,
|
|
'date': '2025-06-17',
|
|
})
|
|
|
|
self.task.action_fsm_validate()
|
|
self.assertEqual(
|
|
self.task.sale_line_id.price_unit,
|
|
pricelist.item_ids[0].fixed_price,
|
|
"The service price does not match the fixed price defined in the customer's pricelist."
|
|
)
|
|
|
|
def test_warranty_status_updates_sale_order_line_price(self):
|
|
"""
|
|
Ensure that the product price is zero in the sales order line
|
|
when the task is under warranty.
|
|
Test Case:
|
|
==========
|
|
1. Create a sales order linked to the customer.
|
|
2. Assign a customer (partner) to the task and link the task to the sales order.
|
|
3. Create a sales order line for a product and link it to the task.
|
|
4. Verify the price unit matches the product's list price by default.
|
|
5. Set the task as under warranty.
|
|
6. Verify the price unit is set to 0.0 in the sales order line.
|
|
7. Unset the warranty status.
|
|
8. Verify the price unit returns to the product's list price.
|
|
"""
|
|
so = self.env['sale.order'].create([{
|
|
'name': 'Test SO linked to fsm task',
|
|
'partner_id': self.partner_1.id,
|
|
}])
|
|
self.task.write({'partner_id': self.partner_1.id, 'sale_order_id': so})
|
|
sol = self.env['sale.order.line'].create([{
|
|
'name': 'Test SOL linked to a fsm tasl',
|
|
'order_id': so.id,
|
|
'task_id': self.task.id,
|
|
'product_id': self.consu_product_delivered.id,
|
|
'product_uom_qty': 3,
|
|
}])
|
|
|
|
self.assertEqual(sol.price_unit, self.consu_product_delivered.list_price,
|
|
"The price should match the product's listed price.")
|
|
self.task.under_warranty = True
|
|
self.assertEqual(sol.price_unit, 0.0,
|
|
"If task is under warranty, the price of the sale order line should be 0.0")
|
|
self.task.under_warranty = False
|
|
self.assertEqual(sol.price_unit, self.consu_product_delivered.list_price,
|
|
"The price should match the product's listed price.")
|
|
|
|
def test_no_double_discount_for_fsm_task(self):
|
|
"""
|
|
Test that the timesheet service line only gives discount
|
|
once from the customer's assigned pricelist.
|
|
|
|
Steps to reproduce:
|
|
- Enable discounts
|
|
- Create a discount pricelist that applies to all products.
|
|
- Assign the pricelist to the customer.
|
|
- Create a task linked to that customer.
|
|
- Add a timesheet entry to the task.
|
|
- Mark the task as done.
|
|
- Verify that the price of the timesheet service line
|
|
in the sale order does not have discount applied twice.
|
|
"""
|
|
self.env['res.config.settings'].create({'group_discount_per_so_line': True}).execute()
|
|
|
|
pricelist = self.env['product.pricelist'].create({
|
|
'name': 'Price List',
|
|
'item_ids': [Command.create({
|
|
'applied_on': '3_global',
|
|
'compute_price': 'percentage',
|
|
'percent_price': 10,
|
|
})],
|
|
})
|
|
self.partner.property_product_pricelist = pricelist
|
|
self.task.partner_id = self.partner
|
|
|
|
analytic_line = self.env['account.analytic.line'].create({
|
|
'employee_id': self.employee_user2.id,
|
|
'task_id': self.task.id,
|
|
'unit_amount': 1.0,
|
|
'date': '2025-06-17',
|
|
})
|
|
self.task.action_fsm_validate()
|
|
discounted_price = pricelist._get_product_price(
|
|
self.task.timesheet_product_id, analytic_line.unit_amount
|
|
)
|
|
self.assertEqual(self.task.sale_line_id.price_subtotal, discounted_price)
|