324 lines
12 KiB
Python
324 lines
12 KiB
Python
# pyrefly: ignore [missing-import]
|
|
from odoo.tests.common import TransactionCase
|
|
# pyrefly: ignore [missing-import]
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class TestHostelModels(TransactionCase):
|
|
"""Phase K — Hostel model tests.
|
|
|
|
Tests 1-13: Model creation and business logic.
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
# Campus
|
|
cls.campus = cls.env['education.campus'].create({
|
|
'name': 'Main Campus',
|
|
'code': 'MC',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Academic Year
|
|
cls.academic_year = cls.env['education.academic.year'].create({
|
|
'name': '2025-26',
|
|
'code': 'AY2526',
|
|
'start_date': '2025-06-01',
|
|
'end_date': '2026-05-31',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Academic Term
|
|
cls.academic_term = cls.env['education.academic.term'].create({
|
|
'name': 'Term 1',
|
|
'code': 'T1',
|
|
'academic_year_id': cls.academic_year.id,
|
|
'start_date': '2025-06-01',
|
|
'end_date': '2025-11-30',
|
|
'sequence': 1,
|
|
})
|
|
# Department
|
|
cls.department = cls.env['education.department'].create({
|
|
'name': 'Hostel Engineering',
|
|
'code': 'H-ENG',
|
|
'campus_id': cls.campus.id,
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Level
|
|
cls.level = cls.env['education.academic.level'].create({
|
|
'name': 'Hostel Undergraduate',
|
|
'code': 'H-UG',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Program
|
|
cls.program = cls.env['education.program'].create({
|
|
'name': 'Hostel B.Tech',
|
|
'code': 'H-BTECH',
|
|
'department_id': cls.department.id,
|
|
'level_id': cls.level.id,
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Batch/Semester/Section
|
|
cls.batch = cls.env['education.batch'].create({'name': 'Hostel B1', 'code': 'H-B1', 'company_id': cls.env.company.id})
|
|
cls.semester = cls.env['education.semester'].create({'name': 'Hostel S1', 'code': 'H-S1', 'company_id': cls.env.company.id})
|
|
cls.section = cls.env['education.section'].create({'name': 'Hostel A', 'code': 'H-A', 'company_id': cls.env.company.id})
|
|
|
|
# Hostel
|
|
cls.hostel = cls.env['education.hostel'].create({
|
|
'name': 'Alpha Hostel',
|
|
'code': 'AH',
|
|
'campus_id': cls.campus.id,
|
|
'hostel_type': 'boys',
|
|
'company_id': cls.env.company.id,
|
|
})
|
|
# Floor
|
|
cls.floor = cls.env['education.hostel.floor'].create({
|
|
'hostel_id': cls.hostel.id,
|
|
'name': 'Ground Floor',
|
|
'code': 'GF',
|
|
'sequence': 1,
|
|
})
|
|
# Room
|
|
cls.room = cls.env['education.hostel.room'].create({
|
|
'hostel_id': cls.hostel.id,
|
|
'floor_id': cls.floor.id,
|
|
'name': 'Room 101',
|
|
'room_number': '101',
|
|
'room_type': 'double',
|
|
'capacity': 2,
|
|
'gender': 'male',
|
|
})
|
|
# Bed
|
|
cls.bed1 = cls.env['education.hostel.bed'].create({
|
|
'room_id': cls.room.id,
|
|
'bed_number': '1',
|
|
'code': 'AH-101-1',
|
|
'status': 'available',
|
|
})
|
|
cls.bed2 = cls.env['education.hostel.bed'].create({
|
|
'room_id': cls.room.id,
|
|
'bed_number': '2',
|
|
'code': 'AH-101-2',
|
|
'status': 'available',
|
|
})
|
|
|
|
def _make_student(first, last, gender='male'):
|
|
return cls.env['education.student'].create({
|
|
'first_name': first,
|
|
'last_name': last,
|
|
'gender': gender,
|
|
'campus_id': cls.campus.id,
|
|
'department_id': cls.department.id,
|
|
'program_id': cls.program.id,
|
|
'level_id': cls.level.id,
|
|
'academic_year_id': cls.academic_year.id,
|
|
'academic_term_id': cls.academic_term.id,
|
|
'batch_id': cls.batch.id,
|
|
'semester_id': cls.semester.id,
|
|
'section_id': cls.section.id,
|
|
'company_id': cls.env.company.id,
|
|
'email': f'{first.lower()}.{last.lower()}@test.edu',
|
|
})
|
|
|
|
cls.student_a = _make_student('Arjun', 'Kumar', 'male')
|
|
cls.student_b = _make_student('Bharath', 'Raj', 'male')
|
|
cls.student_female = _make_student('Priya', 'Sharma', 'female')
|
|
|
|
# 1. Hostel Creation
|
|
def test_01_hostel_creation(self):
|
|
self.assertEqual(self.hostel.name, 'Alpha Hostel')
|
|
self.assertEqual(self.hostel.code, 'AH')
|
|
self.assertEqual(self.hostel.hostel_type, 'boys')
|
|
self.assertTrue(self.hostel.active)
|
|
|
|
# 2. Hostel Hierarchy
|
|
def test_02_hostel_hierarchy(self):
|
|
self.assertEqual(self.floor.hostel_id, self.hostel)
|
|
self.assertEqual(self.room.hostel_id, self.hostel)
|
|
self.assertEqual(self.room.floor_id, self.floor)
|
|
self.assertEqual(self.bed1.room_id, self.room)
|
|
self.assertEqual(self.bed1.hostel_id, self.hostel)
|
|
|
|
# 3. Room Capacity Constraint
|
|
def test_03_room_capacity_constraint(self):
|
|
with self.assertRaises(ValidationError):
|
|
self.env['education.hostel.room'].create({
|
|
'hostel_id': self.hostel.id,
|
|
'floor_id': self.floor.id,
|
|
'name': 'Bad Room',
|
|
'room_number': '999',
|
|
'room_type': 'single',
|
|
'capacity': 0, # invalid
|
|
'gender': 'male',
|
|
})
|
|
|
|
# 4. Bed Uniqueness
|
|
def test_04_bed_code_uniqueness(self):
|
|
with self.assertRaises(ValidationError):
|
|
self.env['education.hostel.bed'].create({
|
|
'room_id': self.room.id,
|
|
'bed_number': '3',
|
|
'code': 'AH-101-1', # duplicate code
|
|
'status': 'available',
|
|
})
|
|
|
|
# 5. Student Allocation
|
|
def test_05_student_allocation(self):
|
|
member = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id,
|
|
'allocation_date': '2025-06-01',
|
|
})
|
|
self.assertEqual(member.status, 'pending')
|
|
member.action_activate()
|
|
self.assertEqual(member.status, 'active')
|
|
self.assertEqual(self.bed1.status, 'occupied')
|
|
return member
|
|
|
|
# 6. Duplicate Active Allocation Blocked
|
|
def test_06_duplicate_active_allocation_blocked(self):
|
|
# Activate first allocation
|
|
m1 = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id,
|
|
'allocation_date': '2025-06-01',
|
|
})
|
|
m1.action_activate()
|
|
# Second active allocation for same student must fail
|
|
with self.assertRaises(ValidationError):
|
|
m2 = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed2.id,
|
|
'allocation_date': '2025-06-01',
|
|
'status': 'active',
|
|
})
|
|
# Cleanup
|
|
m1.action_exit()
|
|
|
|
# 7. Bed Conflict Blocked
|
|
def test_07_bed_conflict_blocked(self):
|
|
m1 = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id,
|
|
'allocation_date': '2025-06-01',
|
|
})
|
|
m1.action_activate()
|
|
with self.assertRaises(ValidationError):
|
|
m2 = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_b.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id, # same bed!
|
|
'allocation_date': '2025-06-01',
|
|
'status': 'active',
|
|
})
|
|
m1.action_exit()
|
|
|
|
# 8. Gender Restriction
|
|
def test_08_gender_restriction(self):
|
|
# room.gender = 'male'; female student should be blocked
|
|
with self.assertRaises(ValidationError):
|
|
self.env['education.hostel.member'].create({
|
|
'student_id': self.student_female.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id,
|
|
'allocation_date': '2025-06-01',
|
|
'status': 'active',
|
|
})
|
|
|
|
# 9. Exit Workflow
|
|
def test_09_exit_workflow(self):
|
|
member = self.env['education.hostel.member'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'room_id': self.room.id,
|
|
'bed_id': self.bed1.id,
|
|
'allocation_date': '2025-06-01',
|
|
})
|
|
member.action_activate()
|
|
self.assertEqual(self.bed1.status, 'occupied')
|
|
member.action_exit()
|
|
self.assertEqual(member.status, 'exited')
|
|
self.assertEqual(self.bed1.status, 'available')
|
|
self.assertTrue(member.actual_exit_date)
|
|
|
|
# 10. Complaint Workflow
|
|
def test_10_complaint_workflow(self):
|
|
complaint = self.env['education.hostel.complaint'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'category': 'maintenance',
|
|
'title': 'Fan not working',
|
|
})
|
|
self.assertEqual(complaint.state, 'draft')
|
|
complaint.action_submit()
|
|
self.assertEqual(complaint.state, 'submitted')
|
|
complaint.assigned_to = self.env.user
|
|
complaint.action_start_progress()
|
|
self.assertEqual(complaint.state, 'in_progress')
|
|
complaint.resolution = 'Fan replaced.'
|
|
complaint.action_resolve()
|
|
self.assertEqual(complaint.state, 'resolved')
|
|
complaint.action_close()
|
|
self.assertEqual(complaint.state, 'closed')
|
|
|
|
# 11. Visitor Workflow
|
|
def test_11_visitor_workflow(self):
|
|
visitor = self.env['education.hostel.visitor'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'visitor_name': 'Parent',
|
|
'relationship': 'Father',
|
|
'visit_date': '2025-07-01',
|
|
})
|
|
self.assertEqual(visitor.state, 'pending')
|
|
visitor.action_approve()
|
|
self.assertEqual(visitor.state, 'approved')
|
|
visitor.action_check_in()
|
|
self.assertEqual(visitor.state, 'checked_in')
|
|
self.assertTrue(visitor.check_in)
|
|
visitor.action_check_out()
|
|
self.assertEqual(visitor.state, 'checked_out')
|
|
|
|
# 12. Fee Structure Creation
|
|
def test_12_fee_structure_creation(self):
|
|
fs = self.env['education.hostel.fee.structure'].create({
|
|
'hostel_id': self.hostel.id,
|
|
'room_type': 'double',
|
|
'amount': 5000.0,
|
|
'billing_period': 'monthly',
|
|
'academic_year_id': self.academic_year.id,
|
|
})
|
|
self.assertEqual(fs.amount, 5000.0)
|
|
self.assertEqual(fs.billing_period, 'monthly')
|
|
|
|
# 13. Fee Validation
|
|
def test_13_fee_validation(self):
|
|
with self.assertRaises(ValidationError):
|
|
self.env['education.hostel.fee.structure'].create({
|
|
'hostel_id': self.hostel.id,
|
|
'room_type': 'single',
|
|
'amount': -100.0, # invalid
|
|
'billing_period': 'monthly',
|
|
})
|
|
# Valid fee creation
|
|
fee = self.env['education.hostel.fee'].create({
|
|
'student_id': self.student_a.id,
|
|
'hostel_id': self.hostel.id,
|
|
'amount': 5000.0,
|
|
'due_date': '2025-07-31',
|
|
})
|
|
self.assertEqual(fee.state, 'draft')
|
|
fee.action_set_due()
|
|
self.assertEqual(fee.state, 'due')
|
|
fee.action_mark_paid()
|
|
self.assertEqual(fee.state, 'paid')
|