diff --git a/account_loan/README.rst b/account_loan/README.rst index 125f8138..6de2d764 100644 --- a/account_loan/README.rst +++ b/account_loan/README.rst @@ -7,7 +7,7 @@ Account Loan management !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:ede8542c931551ec36dabc09621d29b3bcb54586fcad8fd3c4509b95ce8198bf + !! source digest: sha256:c9f87eb07ebda20ab00e0446ae5e5908b6a64086fd868f2bfc58e4e9f7dc68b0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -17,13 +17,13 @@ Account Loan management :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github - :target: https://github.com/OCA/account-financial-tools/tree/14.0/account_loan + :target: https://github.com/OCA/account-financial-tools/tree/16.0/account_loan :alt: OCA/account-financial-tools .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/account-financial-tools-14-0/account-financial-tools-14-0-account_loan + :target: https://translation.odoo-community.org/projects/account-financial-tools-16-0/account-financial-tools-16-0-account_loan :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&target_branch=14.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -68,13 +68,21 @@ On a posted loan you can: :alt: Try me on Runbot :target: https://runbot.odoo-community.org/runbot/92/12.0 +Changelog +========= + +16.0.1.0.0 +~~~~~~~~~~ + +Due to the changes on 16, we will generate two moves on leasings, one for the invoice, and another one for the change from long to short term. + Bug Tracker =========== Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -106,6 +114,14 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/account-financial-tools `_ project on GitHub. +.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px + :target: https://github.com/etobella + :alt: etobella + +Current `maintainer `__: + +|maintainer-etobella| + +This module is part of the `OCA/account-financial-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_loan/__init__.py b/account_loan/__init__.py index b7d72ad1..0aa9b03c 100644 --- a/account_loan/__init__.py +++ b/account_loan/__init__.py @@ -1,4 +1,4 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from . import model -from . import wizard +from . import models +from . import wizards diff --git a/account_loan/__manifest__.py b/account_loan/__manifest__.py index 03bcb7af..7b75d2a4 100644 --- a/account_loan/__manifest__.py +++ b/account_loan/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Account Loan management", - "version": "14.0.1.0.6", + "version": "16.0.1.0.0", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "https://github.com/OCA/account-financial-tools", "license": "AGPL-3", @@ -12,13 +12,14 @@ "data/ir_sequence_data.xml", "security/ir.model.access.csv", "security/account_loan_security.xml", - "wizard/account_loan_generate_entries_view.xml", - "wizard/account_loan_pay_amount_view.xml", - "wizard/account_loan_post_view.xml", + "wizards/account_loan_generate_entries_view.xml", + "wizards/account_loan_pay_amount_view.xml", + "wizards/account_loan_post_view.xml", "views/account_loan_view.xml", "views/account_move_view.xml", ], "installable": True, + "maintainers": ["etobella"], "external_dependencies": { "python": ["numpy>=1.15", "numpy-financial<=1.0.0"], "deb": ["libatlas-base-dev"], diff --git a/account_loan/model/__init__.py b/account_loan/models/__init__.py similarity index 100% rename from account_loan/model/__init__.py rename to account_loan/models/__init__.py diff --git a/account_loan/model/account_loan.py b/account_loan/models/account_loan.py similarity index 92% rename from account_loan/model/account_loan.py rename to account_loan/models/account_loan.py index 6c6949ab..fcf0f429 100644 --- a/account_loan/model/account_loan.py +++ b/account_loan/models/account_loan.py @@ -267,7 +267,7 @@ class AccountLoan(models.Model): if record.loan_type == "fixed-annuity": record.fixed_amount = -record.currency_id.round( numpy_financial.pmt( - record.loan_rate() / 100, + record._loan_rate() / 100, record.fixed_periods, record.fixed_loan_amount, -record.residual_amount, @@ -276,7 +276,7 @@ class AccountLoan(models.Model): elif record.loan_type == "fixed-annuity-begin": record.fixed_amount = -record.currency_id.round( numpy_financial.pmt( - record.loan_rate() / 100, + record._loan_rate() / 100, record.fixed_periods, record.fixed_loan_amount, -record.residual_amount, @@ -292,7 +292,7 @@ class AccountLoan(models.Model): record.fixed_amount = 0.0 @api.model - def compute_rate(self, rate, rate_type, method_period): + def _compute_rate(self, rate, rate_type, method_period): """ Returns the real rate :param rate: Rate @@ -309,10 +309,10 @@ class AccountLoan(models.Model): @api.depends("rate", "method_period", "rate_type") def _compute_rate_period(self): for record in self: - record.rate_period = record.loan_rate() + record.rate_period = record._loan_rate() - def loan_rate(self): - return self.compute_rate(self.rate, self.rate_type, self.method_period) + def _loan_rate(self): + return self._compute_rate(self.rate, self.rate_type, self.method_period) @api.depends("journal_id", "company_id") def _compute_currency(self): @@ -345,20 +345,21 @@ class AccountLoan(models.Model): self.short_term_loan_account_id ) = 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 "/" - @api.model - def create(self, vals): - if vals.get("name", "/") == "/": - vals["name"] = self.get_default_name(vals) - return super().create(vals) + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if vals.get("name", "/") == "/": + vals["name"] = self._get_default_name(vals) + return super().create(vals_list) def post(self): self.ensure_one() if not self.start_date: self.start_date = fields.Date.today() - self.compute_draft_lines() + self._compute_draft_lines() self.write({"state": "posted"}) def close(self): @@ -367,10 +368,10 @@ class AccountLoan(models.Model): def compute_lines(self): self.ensure_one() if self.state == "draft": - return self.compute_draft_lines() - return self.compute_posted_lines() + return self._compute_draft_lines() + return self._compute_posted_lines() - def compute_posted_lines(self): + def _compute_posted_lines(self): """ Recompute the amounts of not finished lines. Useful if rate is changed """ @@ -381,12 +382,12 @@ class AccountLoan(models.Model): else: line.rate = self.rate_period line.pending_principal_amount = amount - line.check_amount() + line._check_amount() amount -= line.payment_amount - line.interests_amount if self.long_term_loan_account_id: - self.check_long_term_principal_amount() + self._check_long_term_principal_amount() - def check_long_term_principal_amount(self): + def _check_long_term_principal_amount(self): """ Recomputes the long term pending principal of unfinished lines. """ @@ -408,7 +409,7 @@ class AccountLoan(models.Model): ) amount = line.long_term_pending_principal_amount - def new_line_vals(self, sequence, date, amount): + def _new_line_vals(self, sequence, date, amount): return { "loan_id": self.id, "sequence": sequence, @@ -417,7 +418,7 @@ class AccountLoan(models.Model): "rate": self.rate_period, } - def compute_draft_lines(self): + def _compute_draft_lines(self): self.ensure_one() self.fixed_periods = self.periods self.fixed_loan_amount = self.loan_amount @@ -432,13 +433,13 @@ class AccountLoan(models.Model): date += delta for i in range(1, self.periods + 1): line = self.env["account.loan.line"].create( - self.new_line_vals(i, date, amount) + self._new_line_vals(i, date, amount) ) - line.check_amount() + line._check_amount() date += delta amount -= line.payment_amount - line.interests_amount if self.long_term_loan_account_id: - self.check_long_term_principal_amount() + self._check_long_term_principal_amount() def view_account_moves(self): self.ensure_one() @@ -457,7 +458,7 @@ class AccountLoan(models.Model): return result @api.model - def generate_loan_entries(self, date): + def _generate_loan_entries(self, date): """ Generate the moves of unfinished loans before date :param date: @@ -470,16 +471,16 @@ class AccountLoan(models.Model): lines = record.line_ids.filtered( lambda r: r.date <= date and not r.move_ids ) - res += lines.generate_move() + res += lines._generate_move() return res @api.model - def generate_leasing_entries(self, date): + def _generate_leasing_entries(self, date): res = [] for record in self.search( [("state", "=", "posted"), ("is_leasing", "=", True)] ): res += record.line_ids.filtered( lambda r: r.date <= date and not r.move_ids - ).generate_invoice() + )._generate_invoice() return res diff --git a/account_loan/model/account_loan_line.py b/account_loan/models/account_loan_line.py similarity index 85% rename from account_loan/model/account_loan_line.py rename to account_loan/models/account_loan_line.py index 6bfaa381..47313f62 100644 --- a/account_loan/model/account_loan_line.py +++ b/account_loan/models/account_loan_line.py @@ -3,7 +3,7 @@ import logging -from odoo import _, api, fields, models +from odoo import Command, _, api, fields, models from odoo.exceptions import UserError _logger = logging.getLogger(__name__) @@ -131,7 +131,7 @@ class AccountLoanLine(models.Model): ) rec.principal_amount = rec.payment_amount - rec.interests_amount - def compute_amount(self): + def _compute_amount(self): """ Computes the payment amount :return: Amount to be payed on the annuity @@ -155,7 +155,7 @@ class AccountLoanLine(models.Model): if self.loan_type == "fixed-annuity": return self.currency_id.round( -numpy_financial.pmt( - self.loan_id.loan_rate() / 100, + self.loan_id._loan_rate() / 100, self.loan_id.periods - self.sequence + 1, self.pending_principal_amount, -self.loan_id.residual_amount, @@ -166,7 +166,7 @@ class AccountLoanLine(models.Model): if self.loan_type == "fixed-annuity-begin": return self.currency_id.round( -numpy_financial.pmt( - self.loan_id.loan_rate() / 100, + self.loan_id._loan_rate() / 100, self.loan_id.periods - self.sequence + 1, self.pending_principal_amount, -self.loan_id.residual_amount, @@ -174,7 +174,7 @@ class AccountLoanLine(models.Model): ) ) - def check_amount(self): + def _check_amount(self): """Recompute amounts if the annuity has not been processed""" if self.move_ids: raise UserError( @@ -190,27 +190,27 @@ class AccountLoanLine(models.Model): - self.pending_principal_amount + self.loan_id.residual_amount ) - self.payment_amount = self.currency_id.round(self.compute_amount()) + self.payment_amount = self.currency_id.round(self._compute_amount()) elif not self.loan_id.round_on_end: - self.interests_amount = self.currency_id.round(self.compute_interest()) - self.payment_amount = self.currency_id.round(self.compute_amount()) + self.interests_amount = self.currency_id.round(self._compute_interest()) + self.payment_amount = self.currency_id.round(self._compute_amount()) else: - self.interests_amount = self.compute_interest() - self.payment_amount = self.compute_amount() + self.interests_amount = self._compute_interest() + self.payment_amount = self._compute_amount() - def compute_interest(self): + def _compute_interest(self): if self.loan_type == "fixed-annuity-begin": return -numpy_financial.ipmt( - self.loan_id.loan_rate() / 100, + self.loan_id._loan_rate() / 100, 2, self.loan_id.periods - self.sequence + 1, self.pending_principal_amount, -self.loan_id.residual_amount, when="begin", ) - return self.pending_principal_amount * self.loan_id.loan_rate() / 100 + return self.pending_principal_amount * self.loan_id._loan_rate() / 100 - def check_move_amount(self): + def _check_move_amount(self): """ Changes the amounts of the annuity once the move is posted :return: @@ -238,17 +238,17 @@ class AccountLoanLine(models.Model): + self.interests_amount ) - def move_vals(self): + def _move_vals(self): return { "loan_line_id": self.id, "loan_id": self.loan_id.id, "date": self.date, "ref": self.name, "journal_id": self.loan_id.journal_id.id, - "line_ids": [(0, 0, vals) for vals in self.move_line_vals()], + "line_ids": [Command.create(vals) for vals in self._move_line_vals()], } - def move_line_vals(self): + def _move_line_vals(self): vals = [] partner = self.loan_id.partner_id.with_company(self.loan_id.company_id) vals.append( @@ -290,7 +290,7 @@ class AccountLoanLine(models.Model): ) return vals - def invoice_vals(self): + def _invoice_vals(self): return { "loan_line_id": self.id, "loan_id": self.loan_id.id, @@ -299,10 +299,12 @@ class AccountLoanLine(models.Model): "invoice_date": self.date, "journal_id": self.loan_id.journal_id.id, "company_id": self.loan_id.company_id.id, - "invoice_line_ids": [(0, 0, vals) for vals in self.invoice_line_vals()], + "invoice_line_ids": [ + Command.create(vals) for vals in self._invoice_line_vals() + ], } - def invoice_line_vals(self): + def _invoice_line_vals(self): vals = list() vals.append( { @@ -324,7 +326,7 @@ class AccountLoanLine(models.Model): ) return vals - def generate_move(self): + def _generate_move(self): """ Computes and post the moves of loans :return: list of account.move generated @@ -336,12 +338,24 @@ class AccountLoanLine(models.Model): lambda r: r.date < record.date and not r.move_ids ): raise UserError(_("Some moves must be created first")) - move = self.env["account.move"].create(record.move_vals()) + move = self.env["account.move"].create(record._move_vals()) move.action_post() res.append(move.id) return res - def generate_invoice(self): + def _long_term_move_vals(self): + return { + "loan_line_id": self.id, + "loan_id": self.loan_id.id, + "date": self.date, + "ref": self.name, + "journal_id": self.loan_id.journal_id.id, + "line_ids": [ + Command.create(vals) for vals in self._get_long_term_move_line_vals() + ], + } + + def _generate_invoice(self): """ Computes invoices of leases :return: list of account.move generated @@ -353,45 +367,37 @@ class AccountLoanLine(models.Model): lambda r: r.date < record.date and not r.move_ids ): raise UserError(_("Some invoices must be created first")) - invoice = self.env["account.move"].create(record.invoice_vals()) + invoice = self.env["account.move"].create(record._invoice_vals()) res.append(invoice.id) for line in invoice.invoice_line_ids: line.tax_ids = line._get_computed_taxes() - invoice.with_context( - check_move_validity=False - )._recompute_dynamic_lines(recompute_all_taxes=True) - invoice._check_balanced() + invoice.flush_recordset() + if record.loan_id.post_invoice: + invoice.action_post() if ( record.long_term_loan_account_id and record.long_term_principal_amount != 0 ): - invoice.write({"line_ids": record._get_long_term_move_line_vals()}) - if record.loan_id.post_invoice: - invoice.action_post() + move = self.env["account.move"].create( + record._long_term_move_vals() + ) + if record.loan_id.post_invoice: + move.action_post() + res.append(move.id) return res def _get_long_term_move_line_vals(self): return [ - ( - 0, - 0, - { - "account_id": self.loan_id.short_term_loan_account_id.id, - "credit": self.long_term_principal_amount, - "debit": 0, - "exclude_from_invoice_tab": True, - }, - ), - ( - 0, - 0, - { - "account_id": self.long_term_loan_account_id.id, - "credit": 0, - "debit": self.long_term_principal_amount, - "exclude_from_invoice_tab": True, - }, - ), + { + "account_id": self.loan_id.short_term_loan_account_id.id, + "credit": self.long_term_principal_amount, + "debit": 0, + }, + { + "account_id": self.long_term_loan_account_id.id, + "credit": 0, + "debit": self.long_term_principal_amount, + }, ] def view_account_values(self): @@ -405,9 +411,9 @@ class AccountLoanLine(models.Model): """Computes the annuity and returns the result""" self.ensure_one() if self.is_leasing: - self.generate_invoice() + self._generate_invoice() else: - self.generate_move() + self._generate_move() return self.view_account_values() def view_account_moves(self): @@ -421,7 +427,7 @@ class AccountLoanLine(models.Model): } result["domain"] = [("loan_line_id", "=", self.id)] if len(self.move_ids) == 1: - res = self.env.ref("account.move.form", False) + res = self.env.ref("account.view_move_form", False) result["views"] = [(res and res.id or False, "form")] result["res_id"] = self.move_ids.id return result @@ -437,7 +443,6 @@ class AccountLoanLine(models.Model): } result["domain"] = [ ("loan_line_id", "=", self.id), - ("move_type", "=", "in_invoice"), ] if len(self.move_ids) == 1: res = self.env.ref("account.view_move_form", False) diff --git a/account_loan/model/account_move.py b/account_loan/models/account_move.py similarity index 78% rename from account_loan/model/account_move.py rename to account_loan/models/account_move.py index 8b58d0c9..695c23ba 100644 --- a/account_loan/model/account_move.py +++ b/account_loan/models/account_move.py @@ -24,11 +24,9 @@ class AccountMove(models.Model): for record in self: loan_line_id = record.loan_line_id if loan_line_id: - if not record.loan_line_id: - record.loan_line_id = loan_line_id record.loan_id = loan_line_id.loan_id - record.loan_line_id.check_move_amount() - record.loan_line_id.loan_id.compute_posted_lines() + record.loan_line_id._check_move_amount() + record.loan_line_id.loan_id._compute_posted_lines() if record.loan_line_id.sequence == record.loan_id.periods: record.loan_id.close() return res diff --git a/account_loan/readme/HISTORY.rst b/account_loan/readme/HISTORY.rst new file mode 100644 index 00000000..b7d6e584 --- /dev/null +++ b/account_loan/readme/HISTORY.rst @@ -0,0 +1,4 @@ +16.0.1.0.0 +~~~~~~~~~~ + +Due to the changes on 16, we will generate two moves on leasings, one for the invoice, and another one for the change from long to short term. diff --git a/account_loan/readme/USAGE.rst b/account_loan/readme/USAGE.rst index cf1355e2..f00e6d94 100644 --- a/account_loan/readme/USAGE.rst +++ b/account_loan/readme/USAGE.rst @@ -1,6 +1,6 @@ To use this module, you need to: -#. Go to `Invoicing / Accounting > Adviser > Loans` +#. Go to `Invoicing / Accounting > Accounting > 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 diff --git a/account_loan/security/ir.model.access.csv b/account_loan/security/ir.model.access.csv index 686286b1..4046d304 100644 --- a/account_loan/security/ir.model.access.csv +++ b/account_loan/security/ir.model.access.csv @@ -3,7 +3,6 @@ access_account_loan,account.loan,model_account_loan,account.group_account_user,1 access_account_loan_manager,account.loan,model_account_loan,account.group_account_manager,1,1,1,1 access_account_loan_line,account.loan.line,model_account_loan_line,account.group_account_user,1,0,0,0 access_account_loan_line_manager,account.loan.line,model_account_loan_line,account.group_account_manager,1,1,1,1 -access_account_loan_generate_wizard,access_account_loan_generate_wizard,model_account_loan_generate_wizard,account.group_account_user,1,0,0,0 -access_account_loan_pay_amount,access_account_loan_pay_amount,model_account_loan_pay_amount,account.group_account_user,1,0,0,0 -access_account_loan_post,access_account_loan_post,model_account_loan_post,account.group_account_user,1,0,0,0 -access_account_loan_post_manager,access_account_loan_post_manager,model_account_loan_post,account.group_account_manager,1,1,1,1 +access_account_loan_generate_wizard,access_account_loan_generate_wizard,model_account_loan_generate_wizard,account.group_account_manager,1,1,1,1 +access_account_loan_pay_amount,access_account_loan_pay_amount,model_account_loan_pay_amount,account.group_account_manager,1,1,1,1 +access_account_loan_post,access_account_loan_post,model_account_loan_post,account.group_account_manager,1,1,1,1 diff --git a/account_loan/static/description/index.html b/account_loan/static/description/index.html index 5c9fd863..8571fd9c 100644 --- a/account_loan/static/description/index.html +++ b/account_loan/static/description/index.html @@ -1,20 +1,20 @@ - + - + Account Loan management