98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
# pyrefly: ignore [missing-import]
|
|
from odoo import api, fields, models
|
|
# pyrefly: ignore [missing-import]
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class EducationHostelRoom(models.Model):
|
|
_name = 'education.hostel.room'
|
|
_description = 'Hostel Room'
|
|
_order = 'hostel_id, room_number'
|
|
_rec_name = 'display_name'
|
|
|
|
hostel_id = fields.Many2one(
|
|
'education.hostel',
|
|
string='Hostel',
|
|
required=True,
|
|
ondelete='restrict',
|
|
index=True,
|
|
)
|
|
floor_id = fields.Many2one(
|
|
'education.hostel.floor',
|
|
string='Floor',
|
|
required=True,
|
|
ondelete='restrict',
|
|
index=True,
|
|
)
|
|
name = fields.Char(string='Room Name', required=True)
|
|
room_number = fields.Char(string='Room Number', required=True, index=True)
|
|
room_type = fields.Selection([
|
|
('single', 'Single'),
|
|
('double', 'Double'),
|
|
('triple', 'Triple'),
|
|
('four', 'Four Sharing'),
|
|
('dormitory', 'Dormitory'),
|
|
('custom', 'Custom'),
|
|
], string='Room Type', default='double', required=True)
|
|
capacity = fields.Integer(string='Capacity', required=True, default=2)
|
|
gender = fields.Selection([
|
|
('male', 'Male'),
|
|
('female', 'Female'),
|
|
('mixed', 'Mixed'),
|
|
], string='Gender', default='mixed', required=True)
|
|
warden_notes = fields.Text(string='Warden Notes')
|
|
active = fields.Boolean(default=True)
|
|
|
|
bed_ids = fields.One2many('education.hostel.bed', 'room_id', string='Beds')
|
|
member_ids = fields.One2many('education.hostel.member', 'room_id', string='Residents')
|
|
|
|
company_id = fields.Many2one(
|
|
'res.company',
|
|
string='Company',
|
|
related='hostel_id.company_id',
|
|
store=True,
|
|
readonly=True,
|
|
index=True,
|
|
)
|
|
|
|
display_name = fields.Char(string='Display Name', compute='_compute_display_name', store=True)
|
|
|
|
# Computed occupancy
|
|
occupied_beds = fields.Integer(string='Occupied Beds', compute='_compute_occupancy', store=False)
|
|
available_beds = fields.Integer(string='Available Beds', compute='_compute_occupancy', store=False)
|
|
occupancy_percentage = fields.Float(string='Occupancy %', compute='_compute_occupancy', store=False)
|
|
|
|
_sql_constraints = [
|
|
('uniq_room_number_hostel', 'unique(room_number, hostel_id)', 'Room number must be unique within the hostel.'),
|
|
]
|
|
|
|
@api.depends('name', 'room_number', 'hostel_id.name')
|
|
def _compute_display_name(self):
|
|
for rec in self:
|
|
rec.display_name = f"{rec.hostel_id.name or ''} / {rec.room_number or ''} - {rec.name or ''}"
|
|
|
|
@api.depends('member_ids', 'member_ids.status', 'capacity')
|
|
def _compute_occupancy(self):
|
|
for rec in self:
|
|
active_members = rec.member_ids.filtered(lambda m: m.status == 'active')
|
|
rec.occupied_beds = len(active_members)
|
|
rec.available_beds = max(0, rec.capacity - rec.occupied_beds)
|
|
rec.occupancy_percentage = (
|
|
round(rec.occupied_beds / rec.capacity * 100, 1)
|
|
if rec.capacity else 0.0
|
|
)
|
|
|
|
@api.constrains('capacity')
|
|
def _check_capacity(self):
|
|
for rec in self:
|
|
if rec.capacity <= 0:
|
|
raise ValidationError('Room capacity must be greater than zero.')
|
|
|
|
@api.constrains('floor_id', 'hostel_id')
|
|
def _check_floor_hostel(self):
|
|
for rec in self:
|
|
if rec.floor_id and rec.floor_id.hostel_id != rec.hostel_id:
|
|
raise ValidationError(
|
|
'The selected floor does not belong to the selected hostel.'
|
|
)
|