496 lines
21 KiB
Python
496 lines
21 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import Command, fields
|
|
from odoo.tests import common, Form, new_test_user
|
|
from odoo.exceptions import AccessError, UserError
|
|
|
|
|
|
class TestRequest(common.TransactionCase):
|
|
def test_compute_request_status(self):
|
|
category_test = self.env.ref('approvals.approval_category_data_business_trip')
|
|
requester_user = self.env.ref('base.user_admin')
|
|
record = self.env['approval.request'].create({
|
|
'name': 'test request',
|
|
'request_owner_id': requester_user.id,
|
|
'category_id': category_test.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
record.write({'approver_ids': [(5, 0, 0)]})
|
|
first_approver = self.env['approval.approver'].create({
|
|
'user_id': 1,
|
|
'request_id': record.id,
|
|
'status': 'new'})
|
|
second_approver = self.env['approval.approver'].create({
|
|
'user_id': 2,
|
|
'request_id': record.id,
|
|
'status': 'new'})
|
|
record.approver_ids = (first_approver | second_approver)
|
|
|
|
def assert_record_request_status_equals(expected_request_status):
|
|
"""
|
|
This helper function will be used to test 2 things:
|
|
1. The real record's expected request_status value
|
|
2. A virtual record's expected request_status, as it would be
|
|
computed in an `onchange` request with a fresh environment
|
|
"""
|
|
self.assertEqual(record.request_status, expected_request_status)
|
|
# Because we are simulating the virtual record behavior as it
|
|
# exists in the context of an `onchange` request, we should make
|
|
# sure that our environment represents that, i.e. we need a clean
|
|
# cache.
|
|
self.env.invalidate_all()
|
|
self.assertEqual(
|
|
record.new(origin=record).request_status,
|
|
expected_request_status)
|
|
|
|
assert_record_request_status_equals('new')
|
|
|
|
record.action_confirm()
|
|
|
|
# Test case 1: Min approval = 1
|
|
assert_record_request_status_equals('pending')
|
|
record.action_approve(first_approver)
|
|
assert_record_request_status_equals('approved')
|
|
record.action_approve(second_approver)
|
|
assert_record_request_status_equals('approved')
|
|
record.action_withdraw(first_approver)
|
|
assert_record_request_status_equals('approved')
|
|
record.action_refuse(first_approver)
|
|
assert_record_request_status_equals('refused')
|
|
|
|
# Test case 2: Min approval = 1
|
|
category_test.approval_minimum = 2
|
|
record.action_withdraw(first_approver)
|
|
record.action_withdraw(second_approver)
|
|
assert_record_request_status_equals('pending')
|
|
record.action_approve(first_approver)
|
|
assert_record_request_status_equals('pending')
|
|
record.action_approve(second_approver)
|
|
assert_record_request_status_equals('approved')
|
|
record.action_withdraw(second_approver)
|
|
assert_record_request_status_equals('pending')
|
|
record.action_refuse(second_approver)
|
|
assert_record_request_status_equals('refused')
|
|
|
|
# Test case 3: Check that cancel is erasing the old validations
|
|
record.action_cancel()
|
|
self.assertEqual(first_approver.status, 'cancel')
|
|
self.assertEqual(second_approver.status, 'cancel')
|
|
assert_record_request_status_equals('cancel')
|
|
|
|
# Test case 4: Set the approval request to draft
|
|
record.action_draft()
|
|
self.assertEqual(first_approver.status, 'new')
|
|
self.assertEqual(second_approver.status, 'new')
|
|
assert_record_request_status_equals('new')
|
|
|
|
# Test case 5: Set min approval to an impossible value to reach
|
|
category_test.approval_minimum = 3
|
|
with self.assertRaises(UserError):
|
|
record.action_confirm()
|
|
assert_record_request_status_equals('new')
|
|
|
|
def test_compute_request_status_with_required(self):
|
|
category_test = self.env.ref('approvals.approval_category_data_business_trip')
|
|
requester_user = self.env.ref('base.user_admin')
|
|
record = self.env['approval.request'].create({
|
|
'name': 'test request',
|
|
'request_owner_id': requester_user.id,
|
|
'category_id': category_test.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
record.write({'approver_ids': [(5, 0, 0)]})
|
|
first_approver = self.env['approval.approver'].create({
|
|
'user_id': 1,
|
|
'request_id': record.id,
|
|
'status': 'new',
|
|
'required': True})
|
|
second_approver = self.env['approval.approver'].create({
|
|
'user_id': 2,
|
|
'request_id': record.id,
|
|
'status': 'new'})
|
|
record.approver_ids = (first_approver | second_approver)
|
|
|
|
self.assertEqual(record.request_status, 'new')
|
|
|
|
record.action_confirm()
|
|
|
|
# Min approval = 1 but first approver IS required
|
|
self.assertEqual(record.request_status, 'pending')
|
|
record.action_approve(second_approver)
|
|
# Min approval is met but required approvals are not
|
|
self.assertEqual(record.request_status, 'pending')
|
|
record.action_approve(first_approver)
|
|
self.assertEqual(record.request_status, 'approved')
|
|
|
|
# Min approval = 2
|
|
category_test.approval_minimum = 2
|
|
record.action_withdraw(first_approver)
|
|
record.action_withdraw(second_approver)
|
|
self.assertEqual(record.request_status, 'pending')
|
|
record.action_approve(first_approver)
|
|
# All required approvals are met but not the minimal approval count
|
|
self.assertEqual(record.request_status, 'pending')
|
|
record.action_approve(second_approver)
|
|
self.assertEqual(record.request_status, 'approved')
|
|
|
|
def test_product_line_compute_uom(self):
|
|
category_test = self.env.ref('approvals.approval_category_data_business_trip')
|
|
uom = self.env.ref('uom.product_uom_dozen')
|
|
product = self.env['product.product'].create({
|
|
'name': 'foo',
|
|
'uom_id': uom.id,
|
|
})
|
|
approval = self.env['approval.request'].create({
|
|
'category_id': category_test.id,
|
|
'product_line_ids': [
|
|
Command.create({'product_id': product.id})
|
|
],
|
|
})
|
|
self.assertEqual(approval.product_line_ids.description, 'foo')
|
|
self.assertEqual(approval.product_line_ids.product_uom_id, uom)
|
|
|
|
def test_unlink_approval(self):
|
|
"""
|
|
There is no error when unlinking a draft request with a document attached
|
|
or a binary field filled.
|
|
"""
|
|
approval = self.env['approval.request'].create({
|
|
'name': 'test request',
|
|
'category_id': self.env.ref('approvals.approval_category_data_business_trip').id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
self.env['ir.attachment'].create({
|
|
'name': 'test.file',
|
|
'res_id': approval.id,
|
|
'res_model': 'approval.request',
|
|
})
|
|
|
|
self.env['ir.model.fields'].create({
|
|
'name': 'x_test_field',
|
|
'model_id': self.env.ref('approvals.model_approval_request').id,
|
|
'ttype': 'binary',
|
|
})
|
|
approval.x_test_field = 'test'
|
|
approval.unlink()
|
|
|
|
def test_unlink_multiple_approvals_with_product_line(self):
|
|
"""
|
|
There is no error when unlinking a multiple approval requests with a
|
|
product line.
|
|
"""
|
|
approvals = self.env['approval.request'].create([{
|
|
'name': 'Approval Request 1',
|
|
'category_id': self.env.ref('approvals.approval_category_data_borrow_items').id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland',
|
|
}, {
|
|
'name': 'Approval Request 1',
|
|
'category_id': self.env.ref('approvals.approval_category_data_borrow_items').id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testitems',
|
|
}])
|
|
product_line = self.env['approval.product.line'].create({
|
|
'approval_request_id': approvals[0].id,
|
|
'description': "Description",
|
|
})
|
|
|
|
approvals.unlink()
|
|
self.assertFalse(product_line.exists())
|
|
self.assertFalse(approvals.exists())
|
|
|
|
def test_request_with_automated_sequence(self):
|
|
approval_category = self.env['approval.category'].create({
|
|
'name': 'Test Category',
|
|
'automated_sequence': True,
|
|
'sequence_code': '1234',
|
|
})
|
|
|
|
request_form = Form(self.env['approval.request'])
|
|
request_form.category_id = approval_category
|
|
approval_request = request_form.save()
|
|
self.assertEqual( approval_request.name, '123400001')
|
|
|
|
def test_approval_request_change_category(self):
|
|
user1 = new_test_user(self.env, login='user1')
|
|
user2 = new_test_user(self.env, login='user2')
|
|
category1 = self.env['approval.category'].create({
|
|
'name': 'Test category 1',
|
|
'approver_ids': [
|
|
Command.create({'user_id': user1.id}),
|
|
Command.create({'user_id': user2.id}),
|
|
]
|
|
})
|
|
category2 = self.env['approval.category'].create({
|
|
'name': 'Test category 2',
|
|
'approver_ids': [
|
|
Command.create({'user_id': user1.id})
|
|
]
|
|
})
|
|
approval = self.env['approval.request'].create({
|
|
'name': 'Test request',
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
self.assertEqual(approval.approver_ids.user_id, (user1 + user2))
|
|
approval.write({
|
|
'category_id': category2.id
|
|
})
|
|
self.assertEqual(approval.approver_ids.user_id, user1)
|
|
|
|
def test_approval_request_write_approved(self):
|
|
user_1 = new_test_user(self.env, login="user 1", groups="base.group_user")
|
|
user_2 = new_test_user(self.env, login="user 2", groups="base.group_user")
|
|
|
|
category_test = self.env.ref('approvals.approval_category_data_business_trip')
|
|
record = self.env['approval.request'].create({
|
|
'name': 'test request',
|
|
'request_owner_id': user_1.id,
|
|
'category_id': category_test.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
first_approver = self.env['approval.approver'].create({
|
|
'user_id': user_2.id,
|
|
'request_id': record.id,
|
|
'status': 'new'
|
|
})
|
|
record.approver_ids = first_approver
|
|
|
|
# approval owner can write on his approval
|
|
record.with_user(user_1).write({'amount': 10})
|
|
|
|
record.action_confirm()
|
|
self.assertEqual(record.request_status, 'pending')
|
|
|
|
record.action_approve(first_approver)
|
|
|
|
self.assertEqual(record.request_status, 'approved')
|
|
# approval owner cannot write on approved approval
|
|
with self.assertRaises(AccessError):
|
|
record.with_user(user_1).write({'amount': 20})
|
|
record.with_user(user_2).write({'amount': 20})
|
|
|
|
# approval owner can cancel
|
|
record.with_user(user_1).write({'request_status': 'cancel'})
|
|
self.assertEqual(record.request_status, 'cancel')
|
|
|
|
record.action_draft()
|
|
self.assertEqual(record.request_status, 'new')
|
|
|
|
# approval owner cannot approved his own approval
|
|
with self.assertRaises(AccessError):
|
|
record.with_user(user_1).write({'request_status': 'approved'})
|
|
|
|
def test_approval_approvers_access(self):
|
|
user1 = new_test_user(self.env, login='user1')
|
|
user2 = new_test_user(self.env, login='user2')
|
|
user3 = new_test_user(self.env, login='user3', groups='approvals.group_approval_user')
|
|
category1 = self.env['approval.category'].create({
|
|
'name': 'Test category 1',
|
|
'company_id': user1.company_id.id,
|
|
'approver_ids': [
|
|
Command.create({'user_id': user2.id}),
|
|
]
|
|
})
|
|
approval = self.env['approval.request'].with_user(user1).create({
|
|
'name': 'Test request',
|
|
'request_owner_id': user1.id,
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
|
|
# Only an officer can edit an approver
|
|
with self.assertRaises(AccessError):
|
|
approval.approver_ids.with_user(user1).write({'required': True})
|
|
approval.approver_ids.with_user(user3).write({'required': True})
|
|
self.assertTrue(approval.approver_ids.required)
|
|
|
|
# Only an officer can add an approver to the request
|
|
with self.assertRaises(AccessError):
|
|
self.env['approval.approver'].with_user(user1).create({'user_id': user3.id, 'request_id': approval.id})
|
|
self.env['approval.approver'].with_user(user3).create({'user_id': user3.id, 'request_id': approval.id})
|
|
self.assertEqual(len(approval.approver_ids), 2)
|
|
|
|
approver2 = approval.approver_ids.filtered(lambda a: a.user_id.id == user2.id)
|
|
approver3 = approval.approver_ids.filtered(lambda a: a.user_id.id == user3.id)
|
|
|
|
# user1 cannot approve the user 2 approver, but user 2 can
|
|
with self.assertRaises(AccessError):
|
|
approver2.with_user(user1).action_approve()
|
|
approver2.with_user(user2).action_approve()
|
|
self.assertEqual(approver2.status, 'approved')
|
|
|
|
# Officer can access, and user2 can access because they are the approver
|
|
approver2.with_user(user2).read()
|
|
approver2.with_user(user3).read()
|
|
|
|
# Only officer can read the approvers
|
|
with self.assertRaises(AccessError):
|
|
approver3.with_user(user2).read()
|
|
approver3.with_user(user3).read()
|
|
|
|
# Only officer can unlink an approver
|
|
with self.assertRaises(AccessError):
|
|
approver3.with_user(user1).unlink()
|
|
approver3.with_user(user3).unlink()
|
|
self.assertEqual(approval.approver_ids.user_id.id, user2.id)
|
|
|
|
def test_consistency_between_request_and_approver(self):
|
|
user = new_test_user(self.env, login='user1', groups='base.group_user')
|
|
admin = new_test_user(self.env, login='admin1', groups='approvals.group_approval_manager')
|
|
admin_env = self.env(user=admin)
|
|
|
|
category1 = self.env['approval.category'].create({
|
|
'name': 'Test category 1',
|
|
'approver_ids': [
|
|
Command.create({'user_id': admin.id}),
|
|
]
|
|
})
|
|
|
|
private_approval = admin_env['approval.request'].create({
|
|
'name': 'Test request (admin)',
|
|
'request_owner_id': admin.id,
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
|
|
approval = admin_env['approval.request'].create({
|
|
'name': 'Test request',
|
|
'request_owner_id': admin.id,
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
user_approver = admin_env['approval.approver'].create({
|
|
'user_id': user.id,
|
|
'request_id': approval.id,
|
|
})
|
|
|
|
with self.assertRaises(AccessError):
|
|
user_approver.with_user(user).request_id = private_approval
|
|
|
|
# As admin, create an approver for your own approval with user
|
|
user_approver_for_admin = admin_env['approval.approver'].create({
|
|
'user_id': user.id,
|
|
'request_id': private_approval.id
|
|
})
|
|
user_approval = admin_env['approval.request'].create({
|
|
'name': 'Test request',
|
|
'request_owner_id': user.id,
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
|
|
# As user, try to move your own approver on your own request
|
|
with self.assertRaises(AccessError):
|
|
user_approver_for_admin.with_user(user).request_id = user_approval
|
|
# As user, move your own approver on the same request
|
|
user_approver_for_admin.with_user(user).request_id = private_approval.id
|
|
|
|
# Create an approver without request
|
|
user_approver = self.env['approval.approver'].create({
|
|
'user_id': user.id,
|
|
})
|
|
# Move it to a request
|
|
user_approver.request_id = approval.id
|
|
|
|
def test_employee_in_user_company(self):
|
|
'''Ensure that the correct manager is added as an approver.
|
|
'''
|
|
user = new_test_user(self.env, login='user1', groups='base.group_user')
|
|
manager1 = new_test_user(self.env, login='manager1', groups='approvals.group_approval_manager')
|
|
manager2 = new_test_user(self.env, login='manager2', groups='approvals.group_approval_manager')
|
|
admin = new_test_user(self.env, login='admin1', groups='approvals.group_approval_manager')
|
|
admin_env = self.env(user=admin)
|
|
company2 = self.env['res.company'].create({'name': 'Wrong Company'})
|
|
|
|
# When incorrect employee is added first, it is selected first.
|
|
employee_manager1 = self.env['hr.employee'].create({
|
|
'user_id': manager1.id,
|
|
})
|
|
employee_manager2 = self.env['hr.employee'].create({
|
|
'user_id': manager2.id,
|
|
})
|
|
employee_user_wrong_company = self.env['hr.employee'].create({
|
|
'user_id': user.id,
|
|
'parent_id': employee_manager2.id,
|
|
'company_id': company2.id,
|
|
})
|
|
employee_user_correct_company = self.env['hr.employee'].create({
|
|
'user_id': user.id,
|
|
'parent_id': employee_manager1.id,
|
|
'company_id': user.company_id.id,
|
|
})
|
|
|
|
category1 = self.env['approval.category'].create({
|
|
'name': 'Test category 1',
|
|
'approver_ids': [
|
|
Command.create({'user_id': admin.id}),
|
|
],
|
|
'manager_approval': 'approver',
|
|
})
|
|
approval = admin_env['approval.request'].create({
|
|
'name': 'Test request',
|
|
'request_owner_id': user.id,
|
|
'category_id': category1.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland'
|
|
})
|
|
|
|
self.assertTrue(employee_user_correct_company.parent_id.user_id in approval.approver_ids.user_id)
|
|
self.assertTrue(employee_user_wrong_company.parent_id.user_id not in approval.approver_ids.user_id)
|
|
|
|
def test_cancel_approver_status_as_non_privileged_user(self):
|
|
"""
|
|
Ensure action_cancel does not raise an AccessError when called by a
|
|
non-privileged user. Previously, writing 'cancel' on approver_ids without
|
|
sudo caused an AccessError.
|
|
"""
|
|
user_1 = new_test_user(self.env, login='user1', groups='base.group_user')
|
|
user_2 = new_test_user(self.env, login='admin1', groups='approvals.group_approval_manager')
|
|
category_test = self.env.ref('approvals.approval_category_data_business_trip')
|
|
record = self.env['approval.request'].create({
|
|
'name': 'test cancel request',
|
|
'request_owner_id': user_1.id,
|
|
'category_id': category_test.id,
|
|
'date_start': fields.Datetime.now(),
|
|
'date_end': fields.Datetime.now(),
|
|
'location': 'testland',
|
|
})
|
|
first_approver = self.env['approval.approver'].create({
|
|
'user_id': user_2.id,
|
|
'request_id': record.id,
|
|
'status': 'new',
|
|
})
|
|
record.approver_ids = first_approver
|
|
record.action_confirm()
|
|
self.assertEqual(record.request_status, 'pending')
|
|
# The approval owner (a plain internal user) cancels the request.
|
|
# Before the fix this raised AccessError because writing on approver_ids
|
|
# was done without sudo. The fix uses sudo() so this must not raise.
|
|
record.with_user(user_1).action_cancel()
|
|
# Approver status must be 'cancel' after the sudo write
|
|
self.assertEqual(first_approver.status, 'cancel')
|
|
self.assertEqual(record.request_status, 'cancel')
|