98 lines
3.9 KiB
Python
98 lines
3.9 KiB
Python
# pyrefly: ignore [missing-import]
|
|
from odoo import api, fields, models
|
|
# pyrefly: ignore [missing-import]
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class EducationStudentPayment(models.Model):
|
|
_name = 'education.student.payment'
|
|
_description = 'Student Payment'
|
|
_order = 'payment_date desc, id desc'
|
|
_rec_name = 'receipt_number'
|
|
|
|
receipt_number = fields.Char(string='Receipt Number', required=True, copy=False, readonly=True, default='/', index=True)
|
|
student_id = fields.Many2one('education.student', string='Student', required=True, index=True)
|
|
payment_date = fields.Date(string='Payment Date', required=True, default=fields.Date.context_today)
|
|
payment_method = fields.Selection([
|
|
('cash', 'Cash'),
|
|
('card', 'Card'),
|
|
('upi', 'UPI'),
|
|
('bank', 'Bank Transfer'),
|
|
('cheque', 'Cheque'),
|
|
('online', 'Online Payment')
|
|
], string='Payment Method', required=True, default='cash')
|
|
|
|
currency_id = fields.Many2one(
|
|
'res.currency',
|
|
string='Currency',
|
|
required=True,
|
|
default=lambda self: self.env.company.currency_id,
|
|
)
|
|
amount = fields.Monetary(string='Amount Paid', required=True, currency_field='currency_id', default=0.0)
|
|
reference_number = fields.Char(string='Reference Number')
|
|
remarks = fields.Text(string='Remarks')
|
|
status = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('confirmed', 'Confirmed'),
|
|
('cancelled', 'Cancelled')
|
|
], string='Status', default='draft', required=True, index=True)
|
|
active = fields.Boolean(default=True)
|
|
company_id = fields.Many2one(
|
|
'res.company',
|
|
string='Company',
|
|
required=True,
|
|
default=lambda self: self.env.company,
|
|
index=True,
|
|
)
|
|
|
|
_sql_constraints = [
|
|
('uniq_receipt_number', 'unique(receipt_number, company_id)', 'Receipt number must be unique per company.'),
|
|
]
|
|
|
|
@api.constrains('amount')
|
|
def _check_amount(self):
|
|
for rec in self:
|
|
if rec.amount <= 0:
|
|
raise ValidationError('Payment amount must be greater than zero.')
|
|
|
|
def action_confirm(self):
|
|
for rec in self:
|
|
if rec.status == 'confirmed':
|
|
continue
|
|
|
|
outstanding = rec.student_id.outstanding_amount
|
|
if rec.amount > outstanding:
|
|
raise ValidationError(f"Cannot accept payment of {rec.amount} because the student's outstanding balance is {outstanding}.")
|
|
|
|
if not rec.receipt_number or rec.receipt_number == '/':
|
|
rec.receipt_number = self.env['ir.sequence'].next_by_code('education.student.payment') or '/'
|
|
|
|
self.env['education.student.ledger'].create({
|
|
'student_id': rec.student_id.id,
|
|
'date': rec.payment_date,
|
|
'ref': rec.receipt_number,
|
|
'description': f"Payment Received - Method: {dict(rec._fields['payment_method'].selection).get(rec.payment_method)} (Ref: {rec.reference_number or 'N/A'})",
|
|
'debit': 0.0,
|
|
'credit': rec.amount,
|
|
'status': 'paid',
|
|
'company_id': rec.company_id.id,
|
|
})
|
|
rec.status = 'confirmed'
|
|
|
|
def action_cancel(self):
|
|
for rec in self:
|
|
if rec.status == 'confirmed':
|
|
ledger_entries = self.env['education.student.ledger'].search([
|
|
('student_id', '=', rec.student_id.id),
|
|
('ref', '=', rec.receipt_number),
|
|
])
|
|
ledger_entries.unlink()
|
|
rec.status = 'cancelled'
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if not vals.get('receipt_number') or vals.get('receipt_number') == '/':
|
|
vals['receipt_number'] = self.env['ir.sequence'].next_by_code('education.student.payment') or '/'
|
|
return super().create(vals_list)
|