117 lines
4.4 KiB
Python

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