In the web client, in a real use case, it's not possible to write on fields which are invisible, as it's not possible to write on fields which are readonly. This is a first step in the goal to change the behavior of the `groups=` attribute in the back-end views, to remove them for the view instead of making them invisible. This is mainly to reduce the diff of the revision that will introduce the mentioned above behavior change. As nodes with `groups=` will be removed from the view when the user doesn't have the group, it's no longer possible to set a value on a field having a `groups=` the user doesn't have in the `Form` test class, as the field will no longer be at all in the view. However, these unit tests shouldn't have been able to set values on invisible fields in the first place. This revision therefore aims to correct the unit tests setting value on fields which were invisible because the user executing the test was not part of the required group(s) for these fields to be visible in the view. closes odoo/odoo#94337 Related: odoo/enterprise#28936 Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
381 lines
18 KiB
Python
381 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
|
from odoo.tests import tagged, Form
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestRepair(AccountTestInvoicingCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls, chart_template_ref=None):
|
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
|
|
|
# Partners
|
|
cls.res_partner_1 = cls.env['res.partner'].create({'name': 'Wood Corner'})
|
|
cls.res_partner_address_1 = cls.env['res.partner'].create({'name': 'Willie Burke', 'parent_id': cls.res_partner_1.id})
|
|
cls.res_partner_12 = cls.env['res.partner'].create({'name': 'Partner 12'})
|
|
|
|
# Products
|
|
cls.product_product_3 = cls.env['product.product'].create({'name': 'Desk Combination'})
|
|
cls.product_product_11 = cls.env['product.product'].create({'name': 'Conference Chair'})
|
|
cls.product_product_5 = cls.env['product.product'].create({'name': 'Product 5'})
|
|
cls.product_product_6 = cls.env['product.product'].create({'name': 'Large Cabinet'})
|
|
cls.product_product_12 = cls.env['product.product'].create({'name': 'Office Chair Black'})
|
|
cls.product_product_13 = cls.env['product.product'].create({'name': 'Corner Desk Left Sit'})
|
|
cls.product_product_2 = cls.env['product.product'].create({'name': 'Virtual Home Staging'})
|
|
cls.product_service_order_repair = cls.env['product.product'].create({
|
|
'name': 'Repair Services',
|
|
'type': 'service',
|
|
})
|
|
|
|
# Location
|
|
cls.stock_warehouse = cls.env['stock.warehouse'].search([('company_id', '=', cls.env.company.id)], limit=1)
|
|
cls.stock_location_14 = cls.env['stock.location'].create({
|
|
'name': 'Shelf 2',
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
})
|
|
|
|
# Repair Orders
|
|
cls.repair1 = cls.env['repair.order'].create({
|
|
'address_id': cls.res_partner_address_1.id,
|
|
'guarantee_limit': '2019-01-01',
|
|
'invoice_method': 'none',
|
|
'user_id': False,
|
|
'product_id': cls.product_product_3.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'partner_invoice_id': cls.res_partner_address_1.id,
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
'operations': [
|
|
(0, 0, {
|
|
'location_dest_id': cls.product_product_11.property_stock_production.id,
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
'name': cls.product_product_11.get_product_multiline_description_sale(),
|
|
'product_id': cls.product_product_11.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'product_uom_qty': 1.0,
|
|
'price_unit': 50.0,
|
|
'state': 'draft',
|
|
'type': 'add',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'fees_lines': [
|
|
(0, 0, {
|
|
'name': cls.product_service_order_repair.get_product_multiline_description_sale(),
|
|
'product_id': cls.product_service_order_repair.id,
|
|
'product_uom_qty': 1.0,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'price_unit': 50.0,
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'partner_id': cls.res_partner_12.id,
|
|
})
|
|
|
|
cls.repair0 = cls.env['repair.order'].create({
|
|
'product_id': cls.product_product_5.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'address_id': cls.res_partner_address_1.id,
|
|
'guarantee_limit': '2019-01-01',
|
|
'invoice_method': 'after_repair',
|
|
'user_id': False,
|
|
'partner_invoice_id': cls.res_partner_address_1.id,
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
'operations': [
|
|
(0, 0, {
|
|
'location_dest_id': cls.product_product_12.property_stock_production.id,
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
'name': cls.product_product_12.get_product_multiline_description_sale(),
|
|
'price_unit': 50.0,
|
|
'product_id': cls.product_product_12.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'product_uom_qty': 1.0,
|
|
'state': 'draft',
|
|
'type': 'add',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'fees_lines': [
|
|
(0, 0, {
|
|
'name': cls.product_service_order_repair.get_product_multiline_description_sale(),
|
|
'product_id': cls.product_service_order_repair.id,
|
|
'product_uom_qty': 1.0,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'price_unit': 50.0,
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'partner_id': cls.res_partner_12.id,
|
|
})
|
|
|
|
cls.repair2 = cls.env['repair.order'].create({
|
|
'product_id': cls.product_product_6.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'address_id': cls.res_partner_address_1.id,
|
|
'guarantee_limit': '2019-01-01',
|
|
'invoice_method': 'b4repair',
|
|
'user_id': False,
|
|
'partner_invoice_id': cls.res_partner_address_1.id,
|
|
'location_id': cls.stock_location_14.id,
|
|
'operations': [
|
|
(0, 0, {
|
|
'location_dest_id': cls.product_product_13.property_stock_production.id,
|
|
'location_id': cls.stock_warehouse.lot_stock_id.id,
|
|
'name': cls.product_product_13.get_product_multiline_description_sale(),
|
|
'price_unit': 50.0,
|
|
'product_id': cls.product_product_13.id,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'product_uom_qty': 1.0,
|
|
'state': 'draft',
|
|
'type': 'add',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'fees_lines': [
|
|
(0, 0, {
|
|
'name': cls.product_service_order_repair.get_product_multiline_description_sale(),
|
|
'product_id': cls.product_service_order_repair.id,
|
|
'product_uom_qty': 1.0,
|
|
'product_uom': cls.env.ref('uom.product_uom_unit').id,
|
|
'price_unit': 50.0,
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
],
|
|
'partner_id': cls.res_partner_12.id,
|
|
})
|
|
|
|
cls.env.user.groups_id |= cls.env.ref('stock.group_stock_user')
|
|
|
|
def _create_simple_repair_order(self, invoice_method):
|
|
product_to_repair = self.product_product_5
|
|
partner = self.res_partner_address_1
|
|
return self.env['repair.order'].create({
|
|
'product_id': product_to_repair.id,
|
|
'product_uom': product_to_repair.uom_id.id,
|
|
'address_id': partner.id,
|
|
'guarantee_limit': '2019-01-01',
|
|
'invoice_method': invoice_method,
|
|
'partner_invoice_id': partner.id,
|
|
'location_id': self.stock_warehouse.lot_stock_id.id,
|
|
'partner_id': self.res_partner_12.id
|
|
})
|
|
|
|
def _create_simple_operation(self, repair_id=False, qty=0.0, price_unit=0.0):
|
|
product_to_add = self.product_product_5
|
|
return self.env['repair.line'].create({
|
|
'name': 'Add The product',
|
|
'type': 'add',
|
|
'product_id': product_to_add.id,
|
|
'product_uom_qty': qty,
|
|
'product_uom': product_to_add.uom_id.id,
|
|
'price_unit': price_unit,
|
|
'repair_id': repair_id,
|
|
'location_id': self.stock_warehouse.lot_stock_id.id,
|
|
'location_dest_id': product_to_add.property_stock_production.id,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
def _create_simple_fee(self, repair_id=False, qty=0.0, price_unit=0.0):
|
|
product_service = self.product_product_2
|
|
return self.env['repair.fee'].create({
|
|
'name': 'PC Assemble + Custom (PC on Demand)',
|
|
'product_id': product_service.id,
|
|
'product_uom_qty': qty,
|
|
'product_uom': product_service.uom_id.id,
|
|
'price_unit': price_unit,
|
|
'repair_id': repair_id,
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
def test_00_repair_afterinv(self):
|
|
repair = self._create_simple_repair_order('after_repair')
|
|
self._create_simple_operation(repair_id=repair.id, qty=1.0, price_unit=50.0)
|
|
# I confirm Repair order taking Invoice Method 'After Repair'.
|
|
repair.action_repair_confirm()
|
|
|
|
# I check the state is in "Confirmed".
|
|
self.assertEqual(repair.state, "confirmed", 'Repair order should be in "Confirmed" state.')
|
|
repair.action_repair_start()
|
|
|
|
# I check the state is in "Under Repair".
|
|
self.assertEqual(repair.state, "under_repair", 'Repair order should be in "Under_repair" state.')
|
|
|
|
# Repairing process for product is in Done state and I end Repair process by clicking on "End Repair" button.
|
|
repair.action_repair_end()
|
|
|
|
# I define Invoice Method 'After Repair' option in this Repair order.so I create invoice by clicking on "Make Invoice" wizard.
|
|
make_invoice = self.env['repair.order.make_invoice'].create({
|
|
'group': True})
|
|
# I click on "Create Invoice" button of this wizard to make invoice.
|
|
context = {
|
|
"active_model": 'repair_order',
|
|
"active_ids": [repair.id],
|
|
"active_id": repair.id
|
|
}
|
|
make_invoice.with_context(context).make_invoices()
|
|
|
|
# I check that invoice is created for this Repair order.
|
|
self.assertEqual(len(repair.invoice_id), 1, "No invoice exists for this repair order")
|
|
self.assertEqual(len(repair.move_id.move_line_ids[0].consume_line_ids), 1, "Consume lines should be set")
|
|
|
|
def test_01_repair_b4inv(self):
|
|
repair = self._create_simple_repair_order('b4repair')
|
|
# I confirm Repair order for Invoice Method 'Before Repair'.
|
|
repair.action_repair_confirm()
|
|
|
|
# I click on "Create Invoice" button of this wizard to make invoice.
|
|
repair.action_repair_invoice_create()
|
|
|
|
# I check that invoice is created for this Repair order.
|
|
self.assertEqual(len(repair.invoice_id), 1, "No invoice exists for this repair order")
|
|
|
|
def test_02_repair_noneinv(self):
|
|
repair = self._create_simple_repair_order('none')
|
|
|
|
# Add a new fee line
|
|
self._create_simple_fee(repair_id=repair.id, qty=1.0, price_unit=12.0)
|
|
|
|
self.assertEqual(repair.amount_total, 12, "Amount_total should be 12")
|
|
# Add new operation line
|
|
self._create_simple_operation(repair_id=repair.id, qty=1.0, price_unit=14.0)
|
|
|
|
self.assertEqual(repair.amount_total, 26, "Amount_total should be 26")
|
|
|
|
# I confirm Repair order for Invoice Method 'No Invoice'.
|
|
repair.action_repair_confirm()
|
|
|
|
# I start the repairing process by clicking on "Start Repair" button for Invoice Method 'No Invoice'.
|
|
repair.action_repair_start()
|
|
|
|
# I check its state which is in "Under Repair".
|
|
self.assertEqual(repair.state, "under_repair", 'Repair order should be in "Under_repair" state.')
|
|
|
|
# Repairing process for product is in Done state and I end this process by clicking on "End Repair" button.
|
|
repair.action_repair_end()
|
|
|
|
self.assertEqual(repair.move_id.location_id.id, self.stock_warehouse.lot_stock_id.id,
|
|
'Repaired product was taken in the wrong location')
|
|
self.assertEqual(repair.move_id.location_dest_id.id, self.stock_warehouse.lot_stock_id.id,
|
|
'Repaired product went to the wrong location')
|
|
self.assertEqual(repair.operations.move_id.location_id.id, self.stock_warehouse.lot_stock_id.id,
|
|
'Consumed product was taken in the wrong location')
|
|
self.assertEqual(repair.operations.move_id.location_dest_id.id, self.product_product_5.property_stock_production.id,
|
|
'Consumed product went to the wrong location')
|
|
|
|
# I define Invoice Method 'No Invoice' option in this repair order.
|
|
# So, I check that Invoice has not been created for this repair order.
|
|
self.assertNotEqual(len(repair.invoice_id), 1, "Invoice should not exist for this repair order")
|
|
|
|
def test_repair_state(self):
|
|
repair = self._create_simple_repair_order('b4repair')
|
|
repair.action_repair_confirm()
|
|
repair.action_repair_invoice_create()
|
|
repair.invoice_id.unlink()
|
|
# Repair order state should be changed to 2binvoiced so that new invoice can be created
|
|
self.assertEqual(repair.state, '2binvoiced', 'Repair order should be in 2binvoiced state, if invoice is deleted.')
|
|
repair.action_repair_invoice_create()
|
|
repair.action_repair_cancel()
|
|
# Repair order and linked invoice both should be cancelled.
|
|
self.assertEqual(repair.state, 'cancel', 'Repair order should be in cancel state.')
|
|
self.assertEqual(repair.invoice_id.state, 'cancel', 'Invoice should be in cancel state.')
|
|
repair.action_repair_cancel_draft()
|
|
# Linked invoice should be unlinked
|
|
self.assertEqual(len(repair.invoice_id), 0, "No invoice should be exists for this repair order")
|
|
|
|
def test_03_repair_multicompany(self):
|
|
""" This test ensures that the correct taxes are selected when the user fills in the RO form """
|
|
|
|
company01 = self.env.company
|
|
company02 = self.env['res.company'].create({
|
|
'name': 'SuperCompany',
|
|
})
|
|
|
|
tax01 = self.env["account.tax"].create({
|
|
"name": "C01 Tax",
|
|
"amount": "0.00",
|
|
"company_id": company01.id
|
|
})
|
|
tax02 = self.env["account.tax"].create({
|
|
"name": "C02 Tax",
|
|
"amount": "0.00",
|
|
"company_id": company02.id
|
|
})
|
|
|
|
super_product = self.env['product.template'].create({
|
|
"name": "SuperProduct",
|
|
"taxes_id": [(4, tax01.id), (4, tax02.id)],
|
|
})
|
|
super_variant = super_product.product_variant_id
|
|
self.assertEqual(super_variant.taxes_id, tax01 | tax02)
|
|
|
|
ro_form = Form(self.env['repair.order'])
|
|
ro_form.product_id = super_variant
|
|
ro_form.partner_id = company01.partner_id
|
|
with ro_form.operations.new() as ro_line:
|
|
ro_line.product_id = super_variant
|
|
with ro_form.fees_lines.new() as fee_line:
|
|
fee_line.product_id = super_variant
|
|
repair_order = ro_form.save()
|
|
|
|
# tax02 should not be present since it belongs to the second company.
|
|
self.assertEqual(repair_order.operations.tax_id, tax01)
|
|
self.assertEqual(repair_order.fees_lines.tax_id, tax01)
|
|
|
|
def test_repair_return(self):
|
|
"""Tests functionality of creating a repair directly from a return picking,
|
|
i.e. repair can be made and defaults to appropriate return values. """
|
|
# test return
|
|
# Required for `location_dest_id` to be visible in the view
|
|
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
|
picking_form = Form(self.env['stock.picking'])
|
|
picking_form.picking_type_id = self.stock_warehouse.return_type_id
|
|
picking_form.partner_id = self.res_partner_1
|
|
picking_form.location_dest_id = self.stock_location_14
|
|
return_picking = picking_form.save()
|
|
|
|
# create repair
|
|
res_dict = return_picking.action_repair_return()
|
|
repair_form = Form(self.env[(res_dict.get('res_model'))].with_context(res_dict['context']))
|
|
repair_form.product_id = self.product_product_3
|
|
repair = repair_form.save()
|
|
|
|
# test that the resulting repairs are correctly created
|
|
self.assertEqual(len(return_picking.repair_ids), 1, "A repair order should have been created and linked to original return.")
|
|
for repair in return_picking.repair_ids:
|
|
self.assertEqual(repair.location_id, return_picking.location_dest_id, "Repair location should have defaulted to return destination location")
|
|
self.assertEqual(repair.partner_id, return_picking.partner_id, "Repair customer should have defaulted to return customer")
|
|
|
|
def test_repair_compute_product_uom(self):
|
|
repair = self.env['repair.order'].create({
|
|
'product_id': self.product_product_3.id,
|
|
'operations': [
|
|
(0, 0, {
|
|
'name': 'foo',
|
|
'product_id': self.product_product_11.id,
|
|
'price_unit': 50.0,
|
|
})
|
|
],
|
|
})
|
|
self.assertEqual(repair.product_uom, self.product_product_3.uom_id)
|
|
self.assertEqual(repair.operations[0].product_uom, self.product_product_11.uom_id)
|
|
|
|
def test_repair_compute_location(self):
|
|
repair = self.env['repair.order'].create({
|
|
'product_id': self.product_product_3.id,
|
|
'operations': [
|
|
(0, 0, {
|
|
'name': 'foo',
|
|
'product_id': self.product_product_11.id,
|
|
'price_unit': 50.0,
|
|
})
|
|
],
|
|
})
|
|
self.assertEqual(repair.location_id, self.stock_warehouse.lot_stock_id)
|
|
self.assertEqual(repair.operations[0].location_id, self.stock_warehouse.lot_stock_id)
|
|
location_dest_id = self.env['stock.location'].search([
|
|
('usage', '=', 'production'),
|
|
('company_id', '=', repair.company_id.id),
|
|
], limit=1)
|
|
self.assertEqual(repair.operations[0].location_dest_id, location_dest_id)
|