312 lines
13 KiB
Python
312 lines
13 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime, timedelta
|
|
from odoo.tests.common import TransactionCase, tagged
|
|
from odoo.exceptions import AccessError, ValidationError
|
|
from odoo.tests import Form
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestPortalPlanningIntegration(TransactionCase):
|
|
"""Test d'intégration pour les workflows complets du module portal_planning."""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
# Créer un utilisateur portail
|
|
cls.portal_user = cls.env['res.users'].create({
|
|
'name': 'Portal User',
|
|
'login': 'portal_test_user',
|
|
'email': 'portal_test@example.com',
|
|
'groups_id': [(6, 0, [cls.env.ref('base.group_portal').id])],
|
|
})
|
|
|
|
# Créer un utilisateur manager
|
|
cls.manager_user = cls.env['res.users'].create({
|
|
'name': 'Manager User',
|
|
'login': 'manager_test_user',
|
|
'email': 'manager_test@example.com',
|
|
'groups_id': [(6, 0, [cls.env.ref('planning.group_planning_manager').id])],
|
|
})
|
|
|
|
# Créer un employé lié à l'utilisateur portail
|
|
cls.employee = cls.env['hr.employee'].create({
|
|
'name': 'Test Employee',
|
|
'user_id': cls.portal_user.id,
|
|
})
|
|
|
|
# Créer un rôle de planning
|
|
cls.role = cls.env['planning.role'].create({
|
|
'name': 'Test Role',
|
|
})
|
|
|
|
# Dates pour les tests
|
|
cls.start_datetime = datetime.now().replace(hour=8, minute=0, second=0, microsecond=0) + timedelta(days=1)
|
|
cls.end_datetime = cls.start_datetime + timedelta(hours=4)
|
|
|
|
def test_01_complete_planning_request_workflow(self):
|
|
"""Test du workflow complet de demande de planning: création, soumission, approbation, confirmation."""
|
|
# 1. Créer une demande de planning en tant qu'utilisateur portail
|
|
request_vals = {
|
|
'name': 'Test Planning Request',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': self.employee.id,
|
|
'user_id': self.portal_user.id,
|
|
'state': 'draft',
|
|
}
|
|
|
|
request = self.env['portal.planning.request'].sudo(self.portal_user).create(request_vals)
|
|
|
|
# Vérifier que la demande est bien créée
|
|
self.assertEqual(request.state, 'draft')
|
|
|
|
# 2. Soumettre la demande
|
|
request.sudo(self.portal_user).action_submit()
|
|
self.assertEqual(request.state, 'submitted')
|
|
|
|
# 3. Approuver la demande en tant que manager
|
|
request.sudo(self.manager_user).action_approve()
|
|
self.assertEqual(request.state, 'approved')
|
|
|
|
# 4. Vérifier qu'un créneau de planning a été créé
|
|
slot = self.env['planning.slot'].sudo().search([
|
|
('employee_id', '=', self.employee.id),
|
|
('start_datetime', '=', self.start_datetime),
|
|
('end_datetime', '=', self.end_datetime),
|
|
], limit=1)
|
|
|
|
self.assertTrue(slot, "Un créneau de planning aurait dû être créé")
|
|
self.assertEqual(slot.role_id, self.role)
|
|
|
|
# 5. Confirmer le créneau en tant qu'utilisateur portail
|
|
slot.sudo(self.portal_user).action_confirm_portal()
|
|
|
|
# Vérifier que le créneau est confirmé
|
|
self.assertEqual(slot.portal_status, 'confirmed')
|
|
self.assertTrue(slot.portal_confirmed)
|
|
|
|
def test_02_complete_planning_modification_workflow(self):
|
|
"""Test du workflow complet de modification de planning: création, modification, approbation."""
|
|
# 1. Créer un créneau de planning
|
|
slot = self.env['planning.slot'].sudo().create({
|
|
'name': 'Test Slot',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': self.employee.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'draft',
|
|
})
|
|
|
|
# 2. Modifier le créneau en tant qu'utilisateur portail
|
|
new_start = self.start_datetime + timedelta(hours=1)
|
|
new_end = self.end_datetime + timedelta(hours=1)
|
|
|
|
# Simuler une modification via le portail
|
|
slot.sudo(self.portal_user).write({
|
|
'portal_start_datetime': new_start,
|
|
'portal_end_datetime': new_end,
|
|
'portal_modified': True,
|
|
'portal_status': 'modified',
|
|
})
|
|
|
|
# Vérifier que le statut a changé
|
|
self.assertEqual(slot.portal_status, 'modified')
|
|
self.assertTrue(slot.portal_modified)
|
|
|
|
# 3. Approuver la modification en tant que manager
|
|
slot.sudo(self.manager_user).action_approve_modification()
|
|
|
|
# Vérifier que les modifications ont été appliquées
|
|
self.assertEqual(slot.start_datetime, new_start)
|
|
self.assertEqual(slot.end_datetime, new_end)
|
|
self.assertEqual(slot.portal_status, 'confirmed')
|
|
self.assertTrue(slot.portal_confirmed)
|
|
self.assertFalse(slot.portal_modified)
|
|
|
|
def test_03_complete_planning_exchange_workflow(self):
|
|
"""Test du workflow complet d'échange de planning: création, soumission, approbation."""
|
|
# 1. Créer un deuxième utilisateur portail et employé
|
|
portal_user2 = self.env['res.users'].create({
|
|
'name': 'Portal User 2',
|
|
'login': 'portal_test_user2',
|
|
'email': 'portal_test2@example.com',
|
|
'groups_id': [(6, 0, [self.env.ref('base.group_portal').id])],
|
|
})
|
|
|
|
employee2 = self.env['hr.employee'].create({
|
|
'name': 'Test Employee 2',
|
|
'user_id': portal_user2.id,
|
|
})
|
|
|
|
# 2. Créer deux créneaux de planning
|
|
slot1 = self.env['planning.slot'].sudo().create({
|
|
'name': 'Slot 1',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': self.employee.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'confirmed',
|
|
'portal_confirmed': True,
|
|
})
|
|
|
|
slot2 = self.env['planning.slot'].sudo().create({
|
|
'name': 'Slot 2',
|
|
'start_datetime': self.start_datetime + timedelta(days=1),
|
|
'end_datetime': self.end_datetime + timedelta(days=1),
|
|
'role_id': self.role.id,
|
|
'employee_id': employee2.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'confirmed',
|
|
'portal_confirmed': True,
|
|
})
|
|
|
|
# 3. Créer une demande d'échange en tant qu'utilisateur portail
|
|
exchange = self.env['portal.planning.exchange'].sudo(self.portal_user).create({
|
|
'name': 'Test Exchange',
|
|
'source_slot_id': slot1.id,
|
|
'target_slot_id': slot2.id,
|
|
'source_user_id': self.portal_user.id,
|
|
'target_user_id': portal_user2.id,
|
|
'state': 'draft',
|
|
'description': 'Test exchange reason',
|
|
})
|
|
|
|
# Vérifier que la demande est bien créée
|
|
self.assertEqual(exchange.state, 'draft')
|
|
|
|
# 4. Soumettre la demande
|
|
exchange.sudo(self.portal_user).action_submit()
|
|
self.assertEqual(exchange.state, 'pending')
|
|
|
|
# 5. Approuver la demande en tant que manager
|
|
exchange.sudo(self.manager_user).action_approve()
|
|
self.assertEqual(exchange.state, 'approved')
|
|
|
|
# 6. Vérifier que les employés ont été échangés
|
|
slot1.refresh()
|
|
slot2.refresh()
|
|
|
|
self.assertEqual(slot1.employee_id, employee2)
|
|
self.assertEqual(slot2.employee_id, self.employee)
|
|
|
|
def test_04_integration_with_timesheet(self):
|
|
"""Test de l'intégration avec les feuilles de temps."""
|
|
# Vérifier si les modules nécessaires sont installés
|
|
module_obj = self.env['ir.module.module']
|
|
hr_timesheet_module = module_obj.search([('name', '=', 'hr_timesheet'), ('state', '=', 'installed')])
|
|
project_module = module_obj.search([('name', '=', 'project'), ('state', '=', 'installed')])
|
|
|
|
if not (hr_timesheet_module and project_module):
|
|
self.skipTest("Ce test nécessite les modules 'hr_timesheet' et 'project' installés")
|
|
|
|
try:
|
|
# 1. Créer un projet et une tâche
|
|
project = self.env['project.project'].create({
|
|
'name': 'Test Project',
|
|
})
|
|
|
|
task = self.env['project.task'].create({
|
|
'name': 'Test Task',
|
|
'project_id': project.id,
|
|
})
|
|
|
|
# 2. Créer un créneau de planning avec génération de feuille de temps activée
|
|
slot_vals = {
|
|
'name': 'Test Slot',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': self.employee.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'confirmed',
|
|
'portal_confirmed': True,
|
|
}
|
|
|
|
# Vérifier si les champs liés au timesheet existent
|
|
slot_fields = self.env['planning.slot']._fields
|
|
if 'generate_timesheet' in slot_fields:
|
|
slot_vals['generate_timesheet'] = True
|
|
if 'project_id' in slot_fields:
|
|
slot_vals['project_id'] = project.id
|
|
if 'task_id' in slot_fields:
|
|
slot_vals['task_id'] = task.id
|
|
|
|
slot = self.env['planning.slot'].sudo().create(slot_vals)
|
|
|
|
# 3. Générer la feuille de temps si la méthode existe
|
|
if hasattr(slot, 'action_generate_timesheet'):
|
|
slot.sudo().action_generate_timesheet()
|
|
|
|
# 4. Vérifier qu'une feuille de temps a été créée
|
|
timesheet = self.env['account.analytic.line'].sudo().search([
|
|
('planning_slot_id', '=', slot.id),
|
|
('employee_id', '=', self.employee.id),
|
|
('project_id', '=', project.id),
|
|
('task_id', '=', task.id),
|
|
], limit=1)
|
|
|
|
self.assertTrue(timesheet, "Une feuille de temps aurait dû être créée")
|
|
if hasattr(timesheet, 'unit_amount'):
|
|
self.assertEqual(timesheet.unit_amount, slot.allocated_hours)
|
|
except Exception as e:
|
|
self.skipTest(f"Test ignoré en raison d'une erreur: {e}")
|
|
|
|
|
|
def test_05_portal_access_rights(self):
|
|
"""Test des droits d'accès des utilisateurs du portail."""
|
|
# 1. Créer un créneau de planning pour l'employé
|
|
slot = self.env['planning.slot'].sudo().create({
|
|
'name': 'Test Slot',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': self.employee.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'draft',
|
|
})
|
|
|
|
# 2. Créer un autre employé et un créneau associé
|
|
other_employee = self.env['hr.employee'].create({
|
|
'name': 'Other Employee',
|
|
})
|
|
|
|
other_slot = self.env['planning.slot'].sudo().create({
|
|
'name': 'Other Slot',
|
|
'start_datetime': self.start_datetime,
|
|
'end_datetime': self.end_datetime,
|
|
'role_id': self.role.id,
|
|
'employee_id': other_employee.id,
|
|
'allocated_hours': 4.0,
|
|
'portal_status': 'draft',
|
|
})
|
|
|
|
# 3. Vérifier que l'utilisateur portail peut accéder à son propre créneau
|
|
# mais pas à celui d'un autre employé
|
|
# Note: Nous utilisons search_count car read pourrait lever une exception
|
|
own_slots_count = self.env['planning.slot'].sudo(self.portal_user).search_count([
|
|
('id', '=', slot.id)
|
|
])
|
|
|
|
other_slots_count = self.env['planning.slot'].sudo(self.portal_user).search_count([
|
|
('id', '=', other_slot.id)
|
|
])
|
|
|
|
self.assertEqual(own_slots_count, 1, "L'utilisateur portail devrait pouvoir voir son propre créneau")
|
|
self.assertEqual(other_slots_count, 0, "L'utilisateur portail ne devrait pas pouvoir voir le créneau d'un autre employé")
|
|
|
|
# 4. Vérifier que le manager peut accéder à tous les créneaux
|
|
manager_own_slots_count = self.env['planning.slot'].sudo(self.manager_user).search_count([
|
|
('id', '=', slot.id)
|
|
])
|
|
|
|
manager_other_slots_count = self.env['planning.slot'].sudo(self.manager_user).search_count([
|
|
('id', '=', other_slot.id)
|
|
])
|
|
|
|
self.assertEqual(manager_own_slots_count, 1, "Le manager devrait pouvoir voir tous les créneaux")
|
|
self.assertEqual(manager_other_slots_count, 1, "Le manager devrait pouvoir voir tous les créneaux")
|