2026-09-25 18:00:58 +05:30

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')