117 lines
5.1 KiB
Python

from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from datetime import timedelta
class EducationLibraryIssue(models.Model):
_name = 'education.library.issue'
_description = 'Library Book Issue'
_rec_name = 'name'
_order = 'issue_date desc'
name = fields.Char(string='Reference', required=True, copy=False, readonly=True, default=lambda self: _('New'))
member_id = fields.Many2one('education.library.member', string='Member', required=True)
copy_id = fields.Many2one('education.library.book.copy', string='Book Copy', required=True)
library_id = fields.Many2one('education.library', string='Library', related='copy_id.library_id', store=True)
issue_date = fields.Date(string='Issue Date', default=fields.Date.context_today, required=True)
due_date = fields.Date(string='Due Date', compute='_compute_due_date', store=True, readonly=False)
return_date = fields.Date(string='Return Date')
status = fields.Selection([
('draft', 'Draft'),
('issued', 'Issued'),
('returned', 'Returned'),
('overdue', 'Overdue'),
('cancelled', 'Cancelled')
], string='Status', default='draft', required=True)
remarks = fields.Text(string='Remarks')
fine_amount = fields.Float(string='Fine Amount', compute='_compute_fine_amount')
fine_ids = fields.One2many('education.library.fine', 'issue_id', string='Fines')
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].sudo().next_by_code('education.library.issue') or _('New')
return super().create(vals_list)
@api.depends('issue_date')
def _compute_due_date(self):
loan_days = int(self.env['ir.config_parameter'].sudo().get_param('education_library.loan_period_days', 14))
for record in self:
if record.issue_date and not record.due_date:
record.due_date = record.issue_date + timedelta(days=loan_days)
@api.depends('fine_ids', 'fine_ids.amount')
def _compute_fine_amount(self):
for record in self:
record.fine_amount = sum(record.fine_ids.mapped('amount'))
@api.constrains('issue_date', 'due_date')
def _check_dates(self):
for record in self:
if record.due_date < record.issue_date:
raise ValidationError(_('Due date must be greater than or equal to issue date.'))
def action_issue(self):
for record in self:
if record.copy_id.status != 'available':
raise ValidationError(_('The selected book copy is not available for issue.'))
if not record.member_id.active:
raise ValidationError(_('Active member required.'))
if record.member_id.membership_end and record.member_id.membership_end < fields.Date.today():
raise ValidationError(_('Membership dates do not permit issue.'))
# Check issue limit
active_issues = self.search_count([
('member_id', '=', record.member_id.id),
('status', 'in', ['issued', 'overdue'])
])
if active_issues >= record.member_id.issue_limit:
raise ValidationError(_('Issue limit enforced: Member has reached their maximum active issues limit.'))
record.copy_id.status = 'issued'
record.status = 'issued'
def action_return(self):
for record in self:
if record.status not in ['issued', 'overdue']:
raise ValidationError(_('Only issued or overdue records can be returned.'))
return_date = fields.Date.today()
record.return_date = return_date
# Calculate fine if late
days_late = max((return_date - record.due_date).days, 0)
if days_late > 0:
fine_per_day = float(self.env['ir.config_parameter'].sudo().get_param('education_library.fine_per_day', 10.0))
fine_amt = days_late * fine_per_day
if fine_amt > 0:
self.env['education.library.fine'].create({
'issue_id': record.id,
'member_id': record.member_id.id,
'student_id': record.member_id.student_id.id if record.member_id.student_id else False,
'days_late': days_late,
'amount': fine_amt,
'state': 'draft'
})
record.copy_id.status = 'available'
record.status = 'returned'
def action_cancel(self):
for record in self:
if record.status not in ['draft']:
raise ValidationError(_('Only draft issues can be cancelled.'))
record.status = 'cancelled'
@api.model
def _cron_mark_overdue(self):
overdue_issues = self.search([
('status', '=', 'issued'),
('due_date', '<', fields.Date.today())
])
overdue_issues.write({'status': 'overdue'})