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