71 lines
4.0 KiB
Python

# pyrefly: ignore [missing-import]
from odoo import api, fields, models
class EducationStudent(models.Model):
_inherit = 'education.student'
ledger_line_ids = fields.One2many('education.student.ledger', 'student_id', string='Ledger Lines')
payment_ids = fields.One2many('education.student.payment', 'student_id', string='Payments')
fee_assignment_ids = fields.One2many('education.fee.assignment', 'student_id', string='Fee Invoices')
currency_id = fields.Many2one('res.currency', string='Currency', related='company_id.currency_id', readonly=True, store=True)
outstanding_amount = fields.Monetary(string='Outstanding Dues', compute='_compute_finance_metrics', currency_field='currency_id', store=True, index=True)
total_fees = fields.Monetary(string='Total Fees', compute='_compute_finance_metrics', currency_field='currency_id', store=True, index=True)
total_paid = fields.Monetary(string='Total Paid', compute='_compute_finance_metrics', currency_field='currency_id', store=True, index=True)
overdue_amount = fields.Monetary(string='Overdue Amount', compute='_compute_finance_metrics', currency_field='currency_id', store=True, index=True)
next_due_date = fields.Date(string='Next Due Date', compute='_compute_finance_metrics', store=True, index=True)
last_payment_date = fields.Date(string='Last Payment Date', compute='_compute_finance_metrics', store=True, index=True)
last_receipt_number = fields.Char(string='Last Receipt Number', compute='_compute_finance_metrics', store=True, index=True)
payment_status = fields.Selection([
('no_dues', 'No Dues'),
('partial', 'Partial'),
('overdue', 'Overdue'),
('fully_paid', 'Fully Paid')
], string='Payment Status', compute='_compute_finance_metrics', default='no_dues', store=True, index=True)
@api.depends(
'ledger_line_ids.debit', 'ledger_line_ids.credit', 'ledger_line_ids.status',
'payment_ids.amount', 'payment_ids.status', 'payment_ids.payment_date', 'payment_ids.receipt_number',
'fee_assignment_ids.state', 'fee_assignment_ids.amount_due', 'fee_assignment_ids.due_date'
)
def _compute_finance_metrics(self):
today = fields.Date.today()
for rec in self:
active_ledgers = rec.ledger_line_ids.filtered(lambda l: l.status in ('outstanding', 'paid'))
total_debits = sum(line.debit for line in active_ledgers)
total_credits = sum(line.credit for line in active_ledgers)
rec.total_fees = total_debits
confirmed_payments = rec.payment_ids.filtered(lambda p: p.status == 'confirmed').sorted(key=lambda p: (p.payment_date or fields.Date.today(), p.id), reverse=True)
rec.total_paid = sum(p.amount for p in confirmed_payments)
rec.outstanding_amount = max(0.0, total_debits - total_credits)
last_payment = confirmed_payments[0] if confirmed_payments else False
rec.last_payment_date = last_payment.payment_date if last_payment else False
rec.last_receipt_number = last_payment.receipt_number if last_payment else False
overdue = 0.0
upcoming_due_dates = []
for a in rec.fee_assignment_ids.filtered(lambda x: x.state == 'confirmed' and x.amount_due > 0):
if a.due_date and a.due_date < today:
overdue += a.amount_due
elif a.due_date and a.due_date >= today:
upcoming_due_dates.append(a.due_date)
rec.overdue_amount = overdue
rec.next_due_date = min(upcoming_due_dates) if upcoming_due_dates else False
if total_debits == 0:
rec.payment_status = 'no_dues'
elif rec.outstanding_amount <= 0:
rec.payment_status = 'fully_paid'
elif overdue > 0:
rec.payment_status = 'overdue'
elif rec.total_paid > 0:
rec.payment_status = 'partial'
else:
rec.payment_status = 'overdue'