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.
		
		
		
		
		
			
		
			
				
					
					
						
							274 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							274 lines
						
					
					
						
							12 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ################################################################################ | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | |
| #    Author: Sabeel (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", store=True, | |
|                                help="Total loan amount", ) | |
|     disbursal_amount = fields.Float(string="Disbursal_amount", | |
|                                     help="Total loan amount " | |
|                                          "available to disburse") | |
|     tenure = fields.Integer(string="Tenure", | |
|                             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", default=False, | |
|                              help="For monitoring the record") | |
|     state = fields.Selection( | |
|         string='State', | |
|         selection=[('draft', 'Draft'), ('confirmed', 'Confirmed'), | |
|                    ('waiting for approval', 'Waiting For Approval'), | |
|                    ('approved', 'Approved'), ('disbursed', 'Disbursed'), | |
|                    ('rejected', 'Rejected'), ('closed', 'Closed')], | |
|         required=True, readonly=True, 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 for approval"}) | |
|         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
 | |
| 
 |