# pyrefly: ignore [missing-import] from odoo import api, fields, models # pyrefly: ignore [missing-import] from odoo.exceptions import ValidationError class EducationHostel(models.Model): _name = 'education.hostel' _description = 'Hostel' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'name' _rec_name = 'name' name = fields.Char(string='Hostel Name', required=True, tracking=True) code = fields.Char(string='Hostel Code', required=True, index=True, tracking=True) campus_id = fields.Many2one( 'education.campus', string='Campus', required=True, ondelete='restrict', index=True, tracking=True, ) hostel_type = fields.Selection([ ('boys', 'Boys'), ('girls', 'Girls'), ('mixed', 'Mixed'), ], string='Hostel Type', required=True, default='boys', tracking=True) warden_id = fields.Many2one( 'res.users', string='Warden', tracking=True, domain=[('share', '=', False)], ) contact_phone = fields.Char(string='Contact Phone') email = fields.Char(string='Email') address = fields.Text(string='Address') description = fields.Text(string='Description') active = fields.Boolean(default=True, tracking=True) company_id = fields.Many2one( 'res.company', string='Company', required=True, default=lambda self: self.env.company, index=True, ) # Relational floor_ids = fields.One2many('education.hostel.floor', 'hostel_id', string='Floors') room_ids = fields.One2many('education.hostel.room', 'hostel_id', string='Rooms') member_ids = fields.One2many('education.hostel.member', 'hostel_id', string='Members') # Computed statistics room_count = fields.Integer(string='Total Rooms', compute='_compute_stats', store=False) bed_count = fields.Integer(string='Total Beds', compute='_compute_stats', store=False) occupied_bed_count = fields.Integer(string='Occupied Beds', compute='_compute_stats', store=False) available_bed_count = fields.Integer(string='Available Beds', compute='_compute_stats', store=False) occupancy_percentage = fields.Float(string='Occupancy %', compute='_compute_stats', store=False) _sql_constraints = [ ('uniq_hostel_code_company', 'unique(code, company_id)', 'Hostel code must be unique per company.'), ] @api.depends('room_ids', 'room_ids.capacity', 'member_ids', 'member_ids.status') def _compute_stats(self): for rec in self: rooms = rec.room_ids.filtered('active') rec.room_count = len(rooms) rec.bed_count = sum(rooms.mapped('capacity')) active_members = rec.member_ids.filtered(lambda m: m.status == 'active') rec.occupied_bed_count = len(active_members) rec.available_bed_count = max(0, rec.bed_count - rec.occupied_bed_count) rec.occupancy_percentage = ( round(rec.occupied_bed_count / rec.bed_count * 100, 1) if rec.bed_count else 0.0 ) @api.constrains('campus_id', 'company_id') def _check_campus_company(self): for rec in self: if rec.campus_id and rec.campus_id.company_id != rec.company_id: raise ValidationError( 'The selected campus does not belong to the current company.' ) def action_view_rooms(self): return { 'type': 'ir.actions.act_window', 'name': 'Rooms', 'res_model': 'education.hostel.room', 'view_mode': 'list,form', 'domain': [('hostel_id', '=', self.id)], 'context': {'default_hostel_id': self.id}, } def action_view_members(self): return { 'type': 'ir.actions.act_window', 'name': 'Active Residents', 'res_model': 'education.hostel.member', 'view_mode': 'list,form', 'domain': [('hostel_id', '=', self.id), ('status', '=', 'active')], 'context': {'default_hostel_id': self.id}, } @api.model_create_multi def create(self, vals_list): for vals in vals_list: if vals.get('code'): vals['code'] = vals['code'].strip().upper() return super().create(vals_list) def write(self, vals): if 'code' in vals and vals.get('code'): vals['code'] = vals['code'].strip().upper() return super().write(vals)