diff --git a/account_loan/__manifest__.py b/account_loan/__manifest__.py index f0fd883f..f14043e4 100644 --- a/account_loan/__manifest__.py +++ b/account_loan/__manifest__.py @@ -1,8 +1,8 @@ # Copyright 2018 Creu Blanca # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - "name": "Account Loan management", - "version": "11.0.1.1.1", + "name": "Account Loan", + "version": "12.0.1.0.0", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "http://github.com/OCA/account-financial-tools", "license": "AGPL-3", diff --git a/account_loan/model/account_loan.py b/account_loan/model/account_loan.py index df85b2a1..2018a194 100644 --- a/account_loan/model/account_loan.py +++ b/account_loan/model/account_loan.py @@ -2,7 +2,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF from datetime import datetime from dateutil.relativedelta import relativedelta @@ -336,9 +335,8 @@ class AccountLoan(models.Model): @api.onchange('company_id') def _onchange_company(self): self._onchange_is_leasing() - self.interest_expenses_account_id = False - self.short_term_loan_account_id = False - self.long_term_loan_account_id = False + self.interest_expenses_account_id = self.short_term_loan_account_id = \ + self.long_term_loan_account_id = False def get_default_name(self, vals): return self.env['ir.sequence'].next_by_code('account.loan') or '/' @@ -353,7 +351,7 @@ class AccountLoan(models.Model): def post(self): self.ensure_one() if not self.start_date: - self.start_date = fields.Datetime.now() + self.start_date = fields.Date.today() self.compute_draft_lines() self.write({'state': 'posted'}) @@ -394,12 +392,11 @@ class AccountLoan(models.Model): return final_sequence = min(lines.mapped('sequence')) for line in lines.sorted('sequence', reverse=True): - date = datetime.strptime( - line.date, DF).date() + relativedelta(months=12) + date = line.date + relativedelta(months=12) if self.state == 'draft' or line.sequence != final_sequence: line.long_term_pending_principal_amount = sum( self.line_ids.filtered( - lambda r: datetime.strptime(r.date, DF).date() >= date + lambda r: r.date >= date ).mapped('principal_amount')) line.long_term_principal_amount = ( line.long_term_pending_principal_amount - amount) @@ -422,7 +419,7 @@ class AccountLoan(models.Model): self.line_ids.unlink() amount = self.loan_amount if self.start_date: - date = datetime.strptime(self.start_date, DF).date() + date = self.start_date else: date = datetime.today().date() delta = relativedelta(months=self.method_period) @@ -470,8 +467,7 @@ class AccountLoan(models.Model): ('is_leasing', '=', False) ]): lines = record.line_ids.filtered( - lambda r: datetime.strptime( - r.date, DF).date() <= date and not r.move_ids + lambda r: r.date <= date and not r.move_ids ) res += lines.generate_move() return res @@ -484,7 +480,6 @@ class AccountLoan(models.Model): ('is_leasing', '=', True) ]): res += record.line_ids.filtered( - lambda r: datetime.strptime( - r.date, DF).date() <= date and not r.invoice_ids + lambda r: r.date <= date and not r.invoice_ids ).generate_invoice() return res diff --git a/account_loan/model/account_move.py b/account_loan/model/account_move.py index bd4e298b..3e83fc3e 100644 --- a/account_loan/model/account_move.py +++ b/account_loan/model/account_move.py @@ -20,8 +20,8 @@ class AccountMove(models.Model): ) @api.multi - def post(self): - res = super().post() + def post(self, invoice=False): + res = super().post(invoice=invoice) for record in self: if record.loan_line_id: record.loan_id = record.loan_line_id.loan_id diff --git a/account_loan/readme/CONTRIBUTORS.rst b/account_loan/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..42054ecf --- /dev/null +++ b/account_loan/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Enric Tobella +* Bhavesh Odedra +* Alberto Martín Cortada diff --git a/account_loan/readme/DESCRIPTION.rst b/account_loan/readme/DESCRIPTION.rst new file mode 100644 index 00000000..42a7a8a9 --- /dev/null +++ b/account_loan/readme/DESCRIPTION.rst @@ -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 `_, + `EAR `_, + `Real Rate `_. +* Leases: a debt with a bank where purchase invoices are necessary diff --git a/account_loan/readme/USAGE.rst b/account_loan/readme/USAGE.rst new file mode 100644 index 00000000..cf1355e2 --- /dev/null +++ b/account_loan/readme/USAGE.rst @@ -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 diff --git a/account_loan/tests/test_loan.py b/account_loan/tests/test_loan.py index dba80094..d018e991 100644 --- a/account_loan/tests/test_loan.py +++ b/account_loan/tests/test_loan.py @@ -4,9 +4,7 @@ from odoo import fields from odoo.exceptions import UserError from odoo.tests import TransactionCase -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF -from datetime import datetime from dateutil.relativedelta import relativedelta import logging @@ -142,36 +140,28 @@ class TestLoan(TransactionCase): 'loan_id': loan.id, 'amount': (amount - amount / periods) / 2, 'fees': 100, - 'date': datetime.strptime( - line.date, DF - ).date() + relativedelta(months=-1) + 'date': line.date + relativedelta(months=-1) }).run() with self.assertRaises(UserError): self.env['account.loan.pay.amount'].create({ 'loan_id': loan.id, 'amount': amount, 'fees': 100, - 'date': datetime.strptime( - line.date, DF - ).date() + 'date': line.date, }).run() with self.assertRaises(UserError): self.env['account.loan.pay.amount'].create({ 'loan_id': loan.id, 'amount': 0, 'fees': 100, - 'date': datetime.strptime( - line.date, DF - ).date() + 'date': line.date, }).run() with self.assertRaises(UserError): self.env['account.loan.pay.amount'].create({ 'loan_id': loan.id, 'amount': -100, 'fees': 100, - 'date': datetime.strptime( - line.date, DF - ).date() + 'date': line.date, }).run() def test_fixed_annuity_loan(self): @@ -258,9 +248,9 @@ class TestLoan(TransactionCase): 'loan_id': loan.id, 'amount': (amount - amount / periods) / 2, 'fees': 100, - 'date': datetime.strptime( - loan.line_ids.filtered(lambda r: r.sequence == 1).date, DF - ).date() + relativedelta(months=-1) + 'date': loan.line_ids.filtered( + lambda r: r.sequence == 1 + ).date + relativedelta(months=-1) }).run() line.invoice_ids.action_invoice_open() self.assertTrue(line.has_moves) @@ -345,9 +335,7 @@ class TestLoan(TransactionCase): self.assertEqual(loan.interests_amount, 0) self.assertEqual(loan.pending_principal_amount, amount) self.assertFalse(loan.line_ids.filtered( - lambda r: ( - datetime.strptime(r.date, DF).date() <= - datetime.strptime(loan.start_date, DF).date()))) + lambda r: r.date <= loan.start_date)) for line in loan.line_ids: self.assertEqual(loan.state, 'posted') line.view_process_values() @@ -396,11 +384,11 @@ class TestLoan(TransactionCase): '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({ 'journal_id': self.journal.id, 'rate_type': 'napr', - 'loan_type': type, + 'loan_type': type_loan, 'loan_amount': amount, 'payment_on_first_period': True, 'rate': rate, diff --git a/account_loan/wizard/account_loan_generate_entries.py b/account_loan/wizard/account_loan_generate_entries.py index be8f2fdf..b777ce60 100644 --- a/account_loan/wizard/account_loan_generate_entries.py +++ b/account_loan/wizard/account_loan_generate_entries.py @@ -1,14 +1,11 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF - -from datetime import datetime class AccountLoanGenerateWizard(models.TransientModel): _name = "account.loan.generate.wizard" + _description = 'Loan generate wizard' date = fields.Date( 'Account Date', @@ -23,7 +20,8 @@ class AccountLoanGenerateWizard(models.TransientModel): def run_leasing(self): 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') result = action.read()[0] if len(created_ids) == 0: @@ -35,8 +33,7 @@ class AccountLoanGenerateWizard(models.TransientModel): return result def run_loan(self): - created_ids = self.env['account.loan'].generate_loan_entries( - datetime.strptime(self.date, DF).date()) + created_ids = self.env['account.loan'].generate_loan_entries(self.date) action = self.env.ref('account.action_move_line_form') result = action.read()[0] if len(created_ids) == 0: diff --git a/account_loan/wizard/account_loan_pay_amount.py b/account_loan/wizard/account_loan_pay_amount.py index 7c0d9fea..de29c992 100644 --- a/account_loan/wizard/account_loan_pay_amount.py +++ b/account_loan/wizard/account_loan_pay_amount.py @@ -7,6 +7,7 @@ from odoo.exceptions import UserError class AccountLoan(models.TransientModel): _name = 'account.loan.pay.amount' + _description = 'Loan pay amount' loan_id = fields.Many2one( 'account.loan', diff --git a/account_loan/wizard/account_loan_post.py b/account_loan/wizard/account_loan_post.py index ae7a6027..4fca2e47 100644 --- a/account_loan/wizard/account_loan_post.py +++ b/account_loan/wizard/account_loan_post.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, fields, models, _ @@ -7,6 +6,7 @@ from odoo.exceptions import UserError class AccountLoanPost(models.TransientModel): _name = "account.loan.post" + _description = 'Loan post' @api.model def _default_journal_id(self):