You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
12 KiB
265 lines
12 KiB
# -*- coding: utf-8 -*-
|
|
################################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
|
|
# Author: Megha (odoo@cybrosys.com)
|
|
#
|
|
# You can modify it under the terms of the GNU AFFERO
|
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
# (AGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
################################################################################
|
|
from datetime import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class LoanRequest(models.Model):
|
|
"""Can create new loan requests and manage records"""
|
|
_name = 'loan.request'
|
|
_inherit = ['mail.thread']
|
|
_description = 'Loan Request'
|
|
|
|
name = fields.Char(string='Loan Reference', readonly=True,
|
|
copy=False, help="Sequence number for loan requests",
|
|
default=lambda self: 'New')
|
|
company_id = fields.Many2one('res.company', string='Company',
|
|
readonly=True,
|
|
help="Company Name",
|
|
default=lambda self: self.env.company)
|
|
currency_id = fields.Many2one('res.currency', string='Currency',
|
|
required=True, help="Currency",
|
|
default=lambda self: self.env.user.company_id.
|
|
currency_id)
|
|
loan_type_id = fields.Many2one('loan.type', string='Loan Type',
|
|
required=True, help="Can choose different "
|
|
"loan types suitable")
|
|
loan_amount = fields.Float(string="Loan Amount",
|
|
help="Total loan amount", )
|
|
disbursal_amount = fields.Float(string="Disbursal Amount",
|
|
help="Total loan amount "
|
|
"available to disburse")
|
|
tenure = fields.Integer(string="Tenure", default=1,
|
|
help="Installment period")
|
|
interest_rate = fields.Float(string="Interest Rate", help="Interest "
|
|
"percentage")
|
|
date = fields.Date(string="Date", default=fields.Date.today(),
|
|
readonly=True, help="Date")
|
|
partner_id = fields.Many2one('res.partner', string="Partner",
|
|
required=True,
|
|
help="Partner")
|
|
repayment_lines_ids = fields.One2many('repayment.line',
|
|
'loan_id',
|
|
string="Loan Line", index=True,
|
|
help="Repayment lines")
|
|
documents_ids = fields.Many2many('loan.documents',
|
|
string="Proofs",
|
|
help="Documents as proof")
|
|
img_attachment_ids = fields.Many2many('ir.attachment',
|
|
relation="m2m_ir_identity_card_rel",
|
|
column1="documents_ids",
|
|
string="Images",
|
|
help="Image proofs")
|
|
journal_id = fields.Many2one('account.journal',
|
|
string="Journal",
|
|
help="Journal types",
|
|
domain="[('type', '=', 'purchase'),"
|
|
"('company_id', '=', company_id)]",
|
|
)
|
|
debit_account_id = fields.Many2one('account.account',
|
|
string="Debit account",
|
|
help="Choose account for "
|
|
"disbursement debit")
|
|
credit_account_id = fields.Many2one('account.account',
|
|
string="Credit account",
|
|
help="Choose account for "
|
|
"disbursement credit")
|
|
reject_reason = fields.Text(string="Reason", help="Displays "
|
|
"rejected reason")
|
|
request = fields.Boolean(string="Request",
|
|
help="For monitoring the record")
|
|
state = fields.Selection(string='State',
|
|
selection=[('draft', 'Draft'), ('confirmed', 'Confirmed'),
|
|
('waiting', 'Waiting For Approval'),
|
|
('approved', 'Approved'), ('disbursed', 'Disbursed'),
|
|
('rejected', 'Rejected'), ('closed', 'Closed')],
|
|
copy=False, tracking=True, default='draft', help="Loan request states")
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
"""create auto sequence for the loan request records"""
|
|
loan_count = self.env['loan.request'].search(
|
|
[('partner_id', '=', vals['partner_id']),
|
|
('state', 'not in', ('draft', 'rejected', 'closed'))])
|
|
if loan_count:
|
|
for rec in loan_count:
|
|
if rec.state != 'closed':
|
|
raise UserError(
|
|
_('The partner has already an ongoing loan.'))
|
|
else:
|
|
if vals.get('name', 'New') == 'New':
|
|
vals['name'] = self.env['ir.sequence'].next_by_code(
|
|
'increment_loan_ref')
|
|
res = super().create(vals)
|
|
return res
|
|
|
|
@api.onchange('loan_type_id')
|
|
def _onchange_loan_type_id(self):
|
|
"""Changing field values based on the chosen loan type"""
|
|
type_id = self.loan_type_id
|
|
self.loan_amount = type_id.loan_amount
|
|
self.disbursal_amount = type_id.disbursal_amount
|
|
self.tenure = type_id.tenure
|
|
self.interest_rate = type_id.interest_rate
|
|
self.documents_ids = type_id.documents_ids
|
|
|
|
def action_loan_request(self):
|
|
"""Changes the state to confirmed and send confirmation mail"""
|
|
self.write({'state': "confirmed"})
|
|
partner = self.partner_id
|
|
loan_no = self.name
|
|
subject = 'Loan Confirmation'
|
|
message = (f"Dear {partner.name},<br/> This is a confirmation mail "
|
|
f"for your loan{loan_no}. We have submitted your loan "
|
|
f"for approval.")
|
|
outgoing_mail = self.company_id.email
|
|
mail_values = {
|
|
'subject': subject,
|
|
'email_from': outgoing_mail,
|
|
'author_id': self.env.user.partner_id.id,
|
|
'email_to': partner.email,
|
|
'body_html': message,
|
|
}
|
|
mail = self.env['mail.mail'].sudo().create(mail_values)
|
|
mail.send()
|
|
|
|
def action_request_for_loan(self):
|
|
"""Change the state to waiting for approval"""
|
|
if self.request:
|
|
self.write({'state': "waiting"})
|
|
else:
|
|
message_id = self.env['message.popup'].create(
|
|
{'message': _("Compute the repayments before requesting")})
|
|
return {
|
|
'name': _('Repayment'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_mode': 'form',
|
|
'res_model': 'message.popup',
|
|
'res_id': message_id.id,
|
|
'target': 'new'
|
|
}
|
|
|
|
def action_loan_approved(self):
|
|
"""Change to Approved state"""
|
|
self.write({'state': "approved"})
|
|
|
|
def action_disburse_loan(self):
|
|
"""Disbursing the loan to customer and creating journal
|
|
entry for the disbursement"""
|
|
self.write({'state': "disbursed"})
|
|
for loan in self:
|
|
amount = loan.disbursal_amount
|
|
loan_name = loan.partner_id.name
|
|
reference = loan.name
|
|
journal_id = loan.journal_id.id
|
|
debit_account_id = loan.debit_account_id.id
|
|
credit_account_id = loan.credit_account_id.id
|
|
date_now = loan.date
|
|
debit_vals = {
|
|
'name': loan_name,
|
|
'account_id': debit_account_id,
|
|
'journal_id': journal_id,
|
|
'date': date_now,
|
|
'debit': amount > 0.0 and amount or 0.0,
|
|
'credit': amount < 0.0 and -amount or 0.0,
|
|
}
|
|
credit_vals = {
|
|
'name': loan_name,
|
|
'account_id': credit_account_id,
|
|
'journal_id': journal_id,
|
|
'date': date_now,
|
|
'debit': amount < 0.0 and -amount or 0.0,
|
|
'credit': amount > 0.0 and amount or 0.0,
|
|
}
|
|
vals = {
|
|
'name': f'DIS / {reference}',
|
|
'narration': reference,
|
|
'ref': reference,
|
|
'journal_id': journal_id,
|
|
'date': date_now,
|
|
'line_ids': [(0, 0, debit_vals), (0, 0, credit_vals)]
|
|
}
|
|
move = self.env['account.move'].create(vals)
|
|
move.action_post()
|
|
return True
|
|
|
|
def action_close_loan(self):
|
|
"""Closing the loan"""
|
|
demo = []
|
|
for check in self.repayment_lines_ids:
|
|
if check.state == 'unpaid':
|
|
demo.append(check)
|
|
if len(demo) >= 1:
|
|
message_id = self.env['message.popup'].create(
|
|
{'message': _("Pending Repayments")})
|
|
return {
|
|
'name': _('Repayment'),
|
|
'type': 'ir.actions.act_window',
|
|
'view_mode': 'form',
|
|
'res_model': 'message.popup',
|
|
'res_id': message_id.id,
|
|
'target': 'new'
|
|
}
|
|
self.write({'state': "closed"})
|
|
|
|
def action_loan_rejected(self):
|
|
"""You can add reject reasons here"""
|
|
return {'type': 'ir.actions.act_window',
|
|
'name': 'Loan Rejection',
|
|
'res_model': 'reject.reason',
|
|
'target': 'new',
|
|
'view_mode': 'form',
|
|
'context': {'default_loan': self.name}
|
|
}
|
|
|
|
def action_compute_repayment(self):
|
|
"""This automatically create the installment the employee need to pay to
|
|
company based on payment start date and the no of installments.
|
|
"""
|
|
self.request = True
|
|
for loan in self:
|
|
loan.repayment_lines_ids.unlink()
|
|
date_start = datetime.strptime(str(loan.date),'%Y-%m-%d') + relativedelta(months=1)
|
|
amount = loan.loan_amount / loan.tenure
|
|
interest = loan.loan_amount * loan.interest_rate
|
|
interest_amount = interest / loan.tenure
|
|
total_amount = amount + interest_amount
|
|
partner = self.partner_id
|
|
for rand_num in range(1, loan.tenure + 1):
|
|
self.env['repayment.line'].create({
|
|
'name': f"{loan.name}/{rand_num}",
|
|
'partner_id': partner.id,
|
|
'date': date_start,
|
|
'amount': amount,
|
|
'interest_amount': interest_amount,
|
|
'total_amount': total_amount,
|
|
'interest_account_id': self.env.ref('advanced_loan_management.'
|
|
'loan_management_'
|
|
'inrst_accounts').id,
|
|
'repayment_account_id': self.env.ref('advanced_loan_management.'
|
|
'demo_'
|
|
'loan_accounts').id,
|
|
'loan_id': loan.id})
|
|
date_start += relativedelta(months=1)
|
|
return True
|
|
|