[MIG] account_loan: Migration to 12.0
This commit is contained in:
parent
b438be5934
commit
7afbbbd5ba
@ -1,8 +1,8 @@
|
|||||||
# Copyright 2018 Creu Blanca
|
# Copyright 2018 Creu Blanca
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
{
|
{
|
||||||
"name": "Account Loan management",
|
"name": "Account Loan",
|
||||||
"version": "11.0.1.1.1",
|
"version": "12.0.1.0.0",
|
||||||
"author": "Creu Blanca,Odoo Community Association (OCA)",
|
"author": "Creu Blanca,Odoo Community Association (OCA)",
|
||||||
"website": "http://github.com/OCA/account-financial-tools",
|
"website": "http://github.com/OCA/account-financial-tools",
|
||||||
"license": "AGPL-3",
|
"license": "AGPL-3",
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
@ -336,9 +335,8 @@ class AccountLoan(models.Model):
|
|||||||
@api.onchange('company_id')
|
@api.onchange('company_id')
|
||||||
def _onchange_company(self):
|
def _onchange_company(self):
|
||||||
self._onchange_is_leasing()
|
self._onchange_is_leasing()
|
||||||
self.interest_expenses_account_id = False
|
self.interest_expenses_account_id = self.short_term_loan_account_id = \
|
||||||
self.short_term_loan_account_id = False
|
self.long_term_loan_account_id = False
|
||||||
self.long_term_loan_account_id = False
|
|
||||||
|
|
||||||
def get_default_name(self, vals):
|
def get_default_name(self, vals):
|
||||||
return self.env['ir.sequence'].next_by_code('account.loan') or '/'
|
return self.env['ir.sequence'].next_by_code('account.loan') or '/'
|
||||||
@ -353,7 +351,7 @@ class AccountLoan(models.Model):
|
|||||||
def post(self):
|
def post(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not self.start_date:
|
if not self.start_date:
|
||||||
self.start_date = fields.Datetime.now()
|
self.start_date = fields.Date.today()
|
||||||
self.compute_draft_lines()
|
self.compute_draft_lines()
|
||||||
self.write({'state': 'posted'})
|
self.write({'state': 'posted'})
|
||||||
|
|
||||||
@ -394,12 +392,11 @@ class AccountLoan(models.Model):
|
|||||||
return
|
return
|
||||||
final_sequence = min(lines.mapped('sequence'))
|
final_sequence = min(lines.mapped('sequence'))
|
||||||
for line in lines.sorted('sequence', reverse=True):
|
for line in lines.sorted('sequence', reverse=True):
|
||||||
date = datetime.strptime(
|
date = line.date + relativedelta(months=12)
|
||||||
line.date, DF).date() + relativedelta(months=12)
|
|
||||||
if self.state == 'draft' or line.sequence != final_sequence:
|
if self.state == 'draft' or line.sequence != final_sequence:
|
||||||
line.long_term_pending_principal_amount = sum(
|
line.long_term_pending_principal_amount = sum(
|
||||||
self.line_ids.filtered(
|
self.line_ids.filtered(
|
||||||
lambda r: datetime.strptime(r.date, DF).date() >= date
|
lambda r: r.date >= date
|
||||||
).mapped('principal_amount'))
|
).mapped('principal_amount'))
|
||||||
line.long_term_principal_amount = (
|
line.long_term_principal_amount = (
|
||||||
line.long_term_pending_principal_amount - amount)
|
line.long_term_pending_principal_amount - amount)
|
||||||
@ -422,7 +419,7 @@ class AccountLoan(models.Model):
|
|||||||
self.line_ids.unlink()
|
self.line_ids.unlink()
|
||||||
amount = self.loan_amount
|
amount = self.loan_amount
|
||||||
if self.start_date:
|
if self.start_date:
|
||||||
date = datetime.strptime(self.start_date, DF).date()
|
date = self.start_date
|
||||||
else:
|
else:
|
||||||
date = datetime.today().date()
|
date = datetime.today().date()
|
||||||
delta = relativedelta(months=self.method_period)
|
delta = relativedelta(months=self.method_period)
|
||||||
@ -470,8 +467,7 @@ class AccountLoan(models.Model):
|
|||||||
('is_leasing', '=', False)
|
('is_leasing', '=', False)
|
||||||
]):
|
]):
|
||||||
lines = record.line_ids.filtered(
|
lines = record.line_ids.filtered(
|
||||||
lambda r: datetime.strptime(
|
lambda r: r.date <= date and not r.move_ids
|
||||||
r.date, DF).date() <= date and not r.move_ids
|
|
||||||
)
|
)
|
||||||
res += lines.generate_move()
|
res += lines.generate_move()
|
||||||
return res
|
return res
|
||||||
@ -484,7 +480,6 @@ class AccountLoan(models.Model):
|
|||||||
('is_leasing', '=', True)
|
('is_leasing', '=', True)
|
||||||
]):
|
]):
|
||||||
res += record.line_ids.filtered(
|
res += record.line_ids.filtered(
|
||||||
lambda r: datetime.strptime(
|
lambda r: r.date <= date and not r.invoice_ids
|
||||||
r.date, DF).date() <= date and not r.invoice_ids
|
|
||||||
).generate_invoice()
|
).generate_invoice()
|
||||||
return res
|
return res
|
||||||
|
@ -20,8 +20,8 @@ class AccountMove(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def post(self):
|
def post(self, invoice=False):
|
||||||
res = super().post()
|
res = super().post(invoice=invoice)
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.loan_line_id:
|
if record.loan_line_id:
|
||||||
record.loan_id = record.loan_line_id.loan_id
|
record.loan_id = record.loan_line_id.loan_id
|
||||||
|
3
account_loan/readme/CONTRIBUTORS.rst
Normal file
3
account_loan/readme/CONTRIBUTORS.rst
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* Enric Tobella <etobella@creublanca.es>
|
||||||
|
* Bhavesh Odedra <bodedra@opensourceintegrators.com>
|
||||||
|
* Alberto Martín Cortada <alberto.martin@guadaltech.es>
|
12
account_loan/readme/DESCRIPTION.rst
Normal file
12
account_loan/readme/DESCRIPTION.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
This module extends the functionality of accounting to support loans.
|
||||||
|
It will create automatically moves or invoices for loans.
|
||||||
|
Moreover, you can check the pending amount to be paid and reduce the debt.
|
||||||
|
|
||||||
|
It currently supports two kinds of debts:
|
||||||
|
|
||||||
|
* Loans: a standard debt with banks, that only creates account moves.
|
||||||
|
Loan types info:
|
||||||
|
`APR <https://en.wikipedia.org/wiki/Annual_percentage_rate>`_,
|
||||||
|
`EAR <https://en.wikipedia.org/wiki/Effective_interest_rate>`_,
|
||||||
|
`Real Rate <https://en.wikipedia.org/wiki/Real_interest_rate>`_.
|
||||||
|
* Leases: a debt with a bank where purchase invoices are necessary
|
18
account_loan/readme/USAGE.rst
Normal file
18
account_loan/readme/USAGE.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
To use this module, you need to:
|
||||||
|
|
||||||
|
#. Go to `Invoicing / Accounting > Adviser > Loans`
|
||||||
|
#. Configure a loan selecting the company, loan type, amount, rate and accounts
|
||||||
|
#. Post the loan, it will automatically create an account move with the
|
||||||
|
expected amounts
|
||||||
|
#. Create automatically the account moves / invoices related to loans and
|
||||||
|
leases before a selected date
|
||||||
|
|
||||||
|
On a posted loan you can:
|
||||||
|
|
||||||
|
* Create moves or invoices (according to the configuration)
|
||||||
|
* Modify rates when needed (only unposted lines will be modified)
|
||||||
|
* Reduce or cancel the debt of a loan / lease
|
||||||
|
|
||||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||||
|
:alt: Try me on Runbot
|
||||||
|
:target: https://runbot.odoo-community.org/runbot/92/12.0
|
@ -4,9 +4,7 @@
|
|||||||
from odoo import fields
|
from odoo import fields
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from odoo.tests import TransactionCase
|
from odoo.tests import TransactionCase
|
||||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -142,36 +140,28 @@ class TestLoan(TransactionCase):
|
|||||||
'loan_id': loan.id,
|
'loan_id': loan.id,
|
||||||
'amount': (amount - amount / periods) / 2,
|
'amount': (amount - amount / periods) / 2,
|
||||||
'fees': 100,
|
'fees': 100,
|
||||||
'date': datetime.strptime(
|
'date': line.date + relativedelta(months=-1)
|
||||||
line.date, DF
|
|
||||||
).date() + relativedelta(months=-1)
|
|
||||||
}).run()
|
}).run()
|
||||||
with self.assertRaises(UserError):
|
with self.assertRaises(UserError):
|
||||||
self.env['account.loan.pay.amount'].create({
|
self.env['account.loan.pay.amount'].create({
|
||||||
'loan_id': loan.id,
|
'loan_id': loan.id,
|
||||||
'amount': amount,
|
'amount': amount,
|
||||||
'fees': 100,
|
'fees': 100,
|
||||||
'date': datetime.strptime(
|
'date': line.date,
|
||||||
line.date, DF
|
|
||||||
).date()
|
|
||||||
}).run()
|
}).run()
|
||||||
with self.assertRaises(UserError):
|
with self.assertRaises(UserError):
|
||||||
self.env['account.loan.pay.amount'].create({
|
self.env['account.loan.pay.amount'].create({
|
||||||
'loan_id': loan.id,
|
'loan_id': loan.id,
|
||||||
'amount': 0,
|
'amount': 0,
|
||||||
'fees': 100,
|
'fees': 100,
|
||||||
'date': datetime.strptime(
|
'date': line.date,
|
||||||
line.date, DF
|
|
||||||
).date()
|
|
||||||
}).run()
|
}).run()
|
||||||
with self.assertRaises(UserError):
|
with self.assertRaises(UserError):
|
||||||
self.env['account.loan.pay.amount'].create({
|
self.env['account.loan.pay.amount'].create({
|
||||||
'loan_id': loan.id,
|
'loan_id': loan.id,
|
||||||
'amount': -100,
|
'amount': -100,
|
||||||
'fees': 100,
|
'fees': 100,
|
||||||
'date': datetime.strptime(
|
'date': line.date,
|
||||||
line.date, DF
|
|
||||||
).date()
|
|
||||||
}).run()
|
}).run()
|
||||||
|
|
||||||
def test_fixed_annuity_loan(self):
|
def test_fixed_annuity_loan(self):
|
||||||
@ -258,9 +248,9 @@ class TestLoan(TransactionCase):
|
|||||||
'loan_id': loan.id,
|
'loan_id': loan.id,
|
||||||
'amount': (amount - amount / periods) / 2,
|
'amount': (amount - amount / periods) / 2,
|
||||||
'fees': 100,
|
'fees': 100,
|
||||||
'date': datetime.strptime(
|
'date': loan.line_ids.filtered(
|
||||||
loan.line_ids.filtered(lambda r: r.sequence == 1).date, DF
|
lambda r: r.sequence == 1
|
||||||
).date() + relativedelta(months=-1)
|
).date + relativedelta(months=-1)
|
||||||
}).run()
|
}).run()
|
||||||
line.invoice_ids.action_invoice_open()
|
line.invoice_ids.action_invoice_open()
|
||||||
self.assertTrue(line.has_moves)
|
self.assertTrue(line.has_moves)
|
||||||
@ -345,9 +335,7 @@ class TestLoan(TransactionCase):
|
|||||||
self.assertEqual(loan.interests_amount, 0)
|
self.assertEqual(loan.interests_amount, 0)
|
||||||
self.assertEqual(loan.pending_principal_amount, amount)
|
self.assertEqual(loan.pending_principal_amount, amount)
|
||||||
self.assertFalse(loan.line_ids.filtered(
|
self.assertFalse(loan.line_ids.filtered(
|
||||||
lambda r: (
|
lambda r: r.date <= loan.start_date))
|
||||||
datetime.strptime(r.date, DF).date() <=
|
|
||||||
datetime.strptime(loan.start_date, DF).date())))
|
|
||||||
for line in loan.line_ids:
|
for line in loan.line_ids:
|
||||||
self.assertEqual(loan.state, 'posted')
|
self.assertEqual(loan.state, 'posted')
|
||||||
line.view_process_values()
|
line.view_process_values()
|
||||||
@ -396,11 +384,11 @@ class TestLoan(TransactionCase):
|
|||||||
'reconcile': True,
|
'reconcile': True,
|
||||||
})
|
})
|
||||||
|
|
||||||
def create_loan(self, type, amount, rate, periods):
|
def create_loan(self, type_loan, amount, rate, periods):
|
||||||
loan = self.env['account.loan'].create({
|
loan = self.env['account.loan'].create({
|
||||||
'journal_id': self.journal.id,
|
'journal_id': self.journal.id,
|
||||||
'rate_type': 'napr',
|
'rate_type': 'napr',
|
||||||
'loan_type': type,
|
'loan_type': type_loan,
|
||||||
'loan_amount': amount,
|
'loan_amount': amount,
|
||||||
'payment_on_first_period': True,
|
'payment_on_first_period': True,
|
||||||
'rate': rate,
|
'rate': rate,
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
|
|
||||||
class AccountLoanGenerateWizard(models.TransientModel):
|
class AccountLoanGenerateWizard(models.TransientModel):
|
||||||
_name = "account.loan.generate.wizard"
|
_name = "account.loan.generate.wizard"
|
||||||
|
_description = 'Loan generate wizard'
|
||||||
|
|
||||||
date = fields.Date(
|
date = fields.Date(
|
||||||
'Account Date',
|
'Account Date',
|
||||||
@ -23,7 +20,8 @@ class AccountLoanGenerateWizard(models.TransientModel):
|
|||||||
|
|
||||||
def run_leasing(self):
|
def run_leasing(self):
|
||||||
created_ids = self.env['account.loan'].generate_leasing_entries(
|
created_ids = self.env['account.loan'].generate_leasing_entries(
|
||||||
datetime.strptime(self.date, DF).date())
|
self.date
|
||||||
|
)
|
||||||
action = self.env.ref('account.action_invoice_tree2')
|
action = self.env.ref('account.action_invoice_tree2')
|
||||||
result = action.read()[0]
|
result = action.read()[0]
|
||||||
if len(created_ids) == 0:
|
if len(created_ids) == 0:
|
||||||
@ -35,8 +33,7 @@ class AccountLoanGenerateWizard(models.TransientModel):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def run_loan(self):
|
def run_loan(self):
|
||||||
created_ids = self.env['account.loan'].generate_loan_entries(
|
created_ids = self.env['account.loan'].generate_loan_entries(self.date)
|
||||||
datetime.strptime(self.date, DF).date())
|
|
||||||
action = self.env.ref('account.action_move_line_form')
|
action = self.env.ref('account.action_move_line_form')
|
||||||
result = action.read()[0]
|
result = action.read()[0]
|
||||||
if len(created_ids) == 0:
|
if len(created_ids) == 0:
|
||||||
|
@ -7,6 +7,7 @@ from odoo.exceptions import UserError
|
|||||||
|
|
||||||
class AccountLoan(models.TransientModel):
|
class AccountLoan(models.TransientModel):
|
||||||
_name = 'account.loan.pay.amount'
|
_name = 'account.loan.pay.amount'
|
||||||
|
_description = 'Loan pay amount'
|
||||||
|
|
||||||
loan_id = fields.Many2one(
|
loan_id = fields.Many2one(
|
||||||
'account.loan',
|
'account.loan',
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
from odoo import api, fields, models, _
|
from odoo import api, fields, models, _
|
||||||
@ -7,6 +6,7 @@ from odoo.exceptions import UserError
|
|||||||
|
|
||||||
class AccountLoanPost(models.TransientModel):
|
class AccountLoanPost(models.TransientModel):
|
||||||
_name = "account.loan.post"
|
_name = "account.loan.post"
|
||||||
|
_description = 'Loan post'
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _default_journal_id(self):
|
def _default_journal_id(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user