diff --git a/account_loan/README.rst b/account_loan/README.rst
index 561fc7c66..9299b0073 100644
--- a/account_loan/README.rst
+++ b/account_loan/README.rst
@@ -14,13 +14,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/12.0/account_loan
+ :target: https://github.com/OCA/account-financial-tools/tree/13.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-12-0/account-financial-tools-12-0-account_loan
+ :target: https://translation.odoo-community.org/projects/account-financial-tools-13-0/account-financial-tools-13-0-account_loan
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
- :target: https://runbot.odoo-community.org/runbot/92/12.0
+ :target: https://runbot.odoo-community.org/runbot/92/13.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -71,7 +71,7 @@ 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 smashing it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -103,6 +103,6 @@ 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.
+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/__manifest__.py b/account_loan/__manifest__.py
index f272f42c9..a049a4b68 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": "12.0.1.1.0",
+ "version": "13.0.1.1.0",
"author": "Creu Blanca,Odoo Community Association (OCA)",
"website": "http://github.com/OCA/account-financial-tools",
"license": "AGPL-3",
@@ -19,5 +19,5 @@
"views/account_move_view.xml",
],
"installable": True,
- "external_dependencies": {"python": ["numpy",],},
+ "external_dependencies": {"python": ["numpy", "numpy-financial<=1.0.0"]},
}
diff --git a/account_loan/i18n/account_loan.pot b/account_loan/i18n/account_loan.pot
index 6176d714f..3b22be62a 100644
--- a/account_loan/i18n/account_loan.pot
+++ b/account_loan/i18n/account_loan.pot
@@ -1,12 +1,12 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
-# * account_loan
+# * account_loan
#
msgid ""
msgstr ""
-"Project-Id-Version: Odoo Server 12.0\n"
+"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
-"Last-Translator: <>\n"
+"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -54,25 +54,30 @@ msgstr ""
msgid "Activities"
msgstr ""
+#. module: account_loan
+#: model:ir.model.fields,field_description:account_loan.field_account_loan__activity_exception_decoration
+msgid "Activity Exception Decoration"
+msgstr ""
+
#. module: account_loan
#: model:ir.model.fields,field_description:account_loan.field_account_loan__activity_state
msgid "Activity State"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:82
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Amount cannot be bigger than debt"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:84
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Amount cannot be less than zero"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/model/account_loan_line.py:186
+#: code:addons/account_loan/model/account_loan_line.py:0
#, python-format
msgid "Amount cannot be recomputed if moves or invoices exists already"
msgstr ""
@@ -125,17 +130,19 @@ msgid "Cancel Loan"
msgstr ""
#. module: account_loan
-#: selection:account.loan,state:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__state__cancelled
msgid "Cancelled"
msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan_generate_wizard__date
-msgid "Choose the period for which you want to automatically post the depreciation lines of running assets"
+msgid ""
+"Choose the period for which you want to automatically post the depreciation "
+"lines of running assets"
msgstr ""
#. module: account_loan
-#: selection:account.loan,state:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__state__closed
msgid "Closed"
msgstr ""
@@ -205,12 +212,12 @@ msgid "Display Name"
msgstr ""
#. module: account_loan
-#: selection:account.loan,state:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__state__draft
msgid "Draft"
msgstr ""
#. module: account_loan
-#: selection:account.loan,rate_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__rate_type__ear
msgid "EAR"
msgstr ""
@@ -225,12 +232,12 @@ msgid "Fixed Amount"
msgstr ""
#. module: account_loan
-#: selection:account.loan,loan_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__loan_type__fixed-annuity
msgid "Fixed Annuity"
msgstr ""
#. module: account_loan
-#: selection:account.loan,loan_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__loan_type__fixed-annuity-begin
msgid "Fixed Annuity Begin"
msgstr ""
@@ -245,7 +252,7 @@ msgid "Fixed Periods"
msgstr ""
#. module: account_loan
-#: selection:account.loan,loan_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__loan_type__fixed-principal
msgid "Fixed Principal"
msgstr ""
@@ -295,17 +302,24 @@ msgid "ID"
msgstr ""
#. module: account_loan
-#: model:ir.model.fields,help:account_loan.field_account_loan__message_unread
-msgid "If checked new messages require your attention."
+#: model:ir.model.fields,field_description:account_loan.field_account_loan__activity_exception_icon
+msgid "Icon"
+msgstr ""
+
+#. module: account_loan
+#: model:ir.model.fields,help:account_loan.field_account_loan__activity_exception_icon
+msgid "Icon to indicate an exception activity."
msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__message_needaction
+#: model:ir.model.fields,help:account_loan.field_account_loan__message_unread
msgid "If checked, new messages require your attention."
msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__message_has_error
+#: model:ir.model.fields,help:account_loan.field_account_loan__message_has_sms_error
msgid "If checked, some messages have a delivery error."
msgstr ""
@@ -324,12 +338,6 @@ msgstr ""
msgid "Interests account"
msgstr ""
-#. module: account_loan
-#: model:ir.model,name:account_loan.model_account_invoice
-#: model:ir.model.fields,field_description:account_loan.field_account_loan_line__invoice_ids
-msgid "Invoice"
-msgstr ""
-
#. module: account_loan
#: model_terms:ir.ui.view,arch_db:account_loan.account_loan_form
msgid "Invoices"
@@ -410,7 +418,7 @@ msgid "Leasing"
msgstr ""
#. module: account_loan
-#: selection:account.loan.generate.wizard,loan_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan_generate_wizard__loan_type__leasing
msgid "Leasings"
msgstr ""
@@ -426,7 +434,6 @@ msgstr ""
#. module: account_loan
#: model:ir.model,name:account_loan.model_account_loan
-#: model:ir.model.fields,field_description:account_loan.field_account_invoice__loan_id
#: model:ir.model.fields,field_description:account_loan.field_account_loan_line__loan_id
#: model:ir.model.fields,field_description:account_loan.field_account_loan_pay_amount__loan_id
#: model:ir.model.fields,field_description:account_loan.field_account_loan_post__loan_id
@@ -441,7 +448,6 @@ msgid "Loan Amount"
msgstr ""
#. module: account_loan
-#: model:ir.model.fields,field_description:account_loan.field_account_invoice__loan_line_id
#: model:ir.model.fields,field_description:account_loan.field_account_move__loan_line_id
msgid "Loan Line"
msgstr ""
@@ -464,7 +470,7 @@ msgid "Loan items"
msgstr ""
#. module: account_loan
-#: sql_constraint:account.loan:0
+#: model:ir.model.constraint,message:account_loan.constraint_account_loan_name_uniq
msgid "Loan name must be unique"
msgstr ""
@@ -484,8 +490,8 @@ msgid "Loan product"
msgstr ""
#. module: account_loan
-#: selection:account.loan.generate.wizard,loan_type:0
#: model:ir.actions.act_window,name:account_loan.account_loan_action
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan_generate_wizard__loan_type__loan
#: model:ir.ui.menu,name:account_loan.account_loan_menu
#: model_terms:ir.ui.view,arch_db:account_loan.account_loan_tree
msgid "Loans"
@@ -566,7 +572,7 @@ msgid "Next Activity Type"
msgstr ""
#. module: account_loan
-#: selection:account.loan,rate_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__rate_type__napr
msgid "Nominal APR"
msgstr ""
@@ -577,7 +583,7 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,field_description:account_loan.field_account_loan__message_has_error_counter
-msgid "Number of error"
+msgid "Number of errors"
msgstr ""
#. module: account_loan
@@ -601,21 +607,16 @@ msgid "Number of unread messages"
msgstr ""
#. module: account_loan
-#: selection:account.loan,loan_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__loan_type__interest
msgid "Only interest"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_post.py:91
+#: code:addons/account_loan/wizard/account_loan_post.py:0
#, python-format
msgid "Only loans in draft state can be posted"
msgstr ""
-#. module: account_loan
-#: selection:account.loan,activity_state:0
-msgid "Overdue"
-msgstr ""
-
#. module: account_loan
#: model:ir.actions.act_window,name:account_loan.account_loan_pay_amount_action
#: model_terms:ir.ui.view,arch_db:account_loan.account_loan_form
@@ -652,7 +653,9 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan_line__long_term_pending_principal_amount
-msgid "Pending amount of the loan before the payment that will not be payed in, at least, 12 months"
+msgid ""
+"Pending amount of the loan before the payment that will not be payed in, at "
+"least, 12 months"
msgstr ""
#. module: account_loan
@@ -665,11 +668,6 @@ msgstr ""
msgid "Periods"
msgstr ""
-#. module: account_loan
-#: selection:account.loan,activity_state:0
-msgid "Planned"
-msgstr ""
-
#. module: account_loan
#: model_terms:ir.ui.view,arch_db:account_loan.account_loan_form
msgid "Post"
@@ -686,7 +684,7 @@ msgid "Post loan"
msgstr ""
#. module: account_loan
-#: selection:account.loan,state:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__state__posted
msgid "Posted"
msgstr ""
@@ -702,12 +700,16 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__interests_product_id
-msgid "Product where the amount of interests will be assigned when the invoice is created"
+msgid ""
+"Product where the amount of interests will be assigned when the invoice is "
+"created"
msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__product_id
-msgid "Product where the amount of the loan will be assigned when the invoice is created"
+msgid ""
+"Product where the amount of the loan will be assigned when the invoice is "
+"created"
msgstr ""
#. module: account_loan
@@ -727,7 +729,7 @@ msgid "Rate Type"
msgstr ""
#. module: account_loan
-#: selection:account.loan,rate_type:0
+#: model:ir.model.fields.selection,name:account_loan.selection__account_loan__rate_type__real
msgid "Real rate"
msgstr ""
@@ -743,7 +745,9 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__residual_amount
-msgid "Residual amount of the lease that must be payed on the end in order to acquire the asset"
+msgid ""
+"Residual amount of the lease that must be payed on the end in order to "
+"acquire the asset"
msgstr ""
#. module: account_loan
@@ -763,13 +767,18 @@ msgstr ""
msgid "Run"
msgstr ""
+#. module: account_loan
+#: model:ir.model.fields,field_description:account_loan.field_account_loan__message_has_sms_error
+msgid "SMS Delivery error"
+msgstr ""
+
#. module: account_loan
#: model:ir.model.fields,field_description:account_loan.field_account_loan_line__sequence
msgid "Sequence"
msgstr ""
#. module: account_loan
-#: sql_constraint:account.loan.line:0
+#: model:ir.model.constraint,message:account_loan.constraint_account_loan_line_sequence_loan
msgid "Sequence must be unique in a loan"
msgstr ""
@@ -779,37 +788,37 @@ msgid "Short term account"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:65
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Some future invoices already exists"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:73
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Some future moves already exists"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:61
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Some invoices are not created"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/model/account_loan_line.py:358
+#: code:addons/account_loan/model/account_loan_line.py:0
#, python-format
msgid "Some invoices must be created first"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/wizard/account_loan_pay_amount.py:69
+#: code:addons/account_loan/wizard/account_loan_pay_amount.py:0
#, python-format
msgid "Some moves are not created"
msgstr ""
#. module: account_loan
-#: code:addons/account_loan/model/account_loan_line.py:340
+#: code:addons/account_loan/model/account_loan_line.py:0
#, python-format
msgid "Some moves must be created first"
msgstr ""
@@ -837,17 +846,13 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__activity_state
-msgid "Status based on activities\n"
+msgid ""
+"Status based on activities\n"
"Overdue: Due date is already passed\n"
"Today: Activity date is today\n"
"Planned: Future activities."
msgstr ""
-#. module: account_loan
-#: selection:account.loan,activity_state:0
-msgid "Today"
-msgstr ""
-
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan_line__payment_amount
msgid "Total amount that will be payed (Annuity)"
@@ -873,6 +878,11 @@ msgstr ""
msgid "Total payments"
msgstr ""
+#. module: account_loan
+#: model:ir.model.fields,help:account_loan.field_account_loan__activity_exception_decoration
+msgid "Type of the exception activity on record."
+msgstr ""
+
#. module: account_loan
#: model:ir.model.fields,field_description:account_loan.field_account_loan__message_unread
msgid "Unread Messages"
@@ -900,7 +910,9 @@ msgstr ""
#. module: account_loan
#: model:ir.model.fields,help:account_loan.field_account_loan__round_on_end
-msgid "When checked, the differences will be applied on the last period, if it is unchecked, the annuity will be recalculated on each period."
+msgid ""
+"When checked, the differences will be applied on the last period, if it is "
+"unchecked, the annuity will be recalculated on each period."
msgstr ""
#. module: account_loan
@@ -914,4 +926,3 @@ msgstr ""
#: model_terms:ir.ui.view,arch_db:account_loan.account_loan_post_form
msgid "or"
msgstr ""
-
diff --git a/account_loan/migrations/13.0.1.1.0/post-migration.py b/account_loan/migrations/13.0.1.1.0/post-migration.py
new file mode 100644
index 000000000..0854e860a
--- /dev/null
+++ b/account_loan/migrations/13.0.1.1.0/post-migration.py
@@ -0,0 +1,16 @@
+# Copyright 2021 Creu Blanca - Alba Riera
+
+from openupgradelib import openupgrade
+
+
+@openupgrade.migrate()
+def migrate(env, version):
+ openupgrade.logged_query(
+ env.cr,
+ """
+ UPDATE account_move am
+ SET loan_line_id = ai.loan_line_id,
+ loan_id = ai.loan_id
+ FROM account_invoice ai
+ WHERE ai.id = am.old_invoice_id and ai.loan_id is not null""",
+ )
diff --git a/account_loan/model/__init__.py b/account_loan/model/__init__.py
index ad26bdeef..d07b9f2fb 100644
--- a/account_loan/model/__init__.py
+++ b/account_loan/model/__init__.py
@@ -1,7 +1,6 @@
# Copyright 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-from . import account_invoice
from . import account_loan
from . import account_loan_line
from . import account_move
diff --git a/account_loan/model/account_invoice.py b/account_loan/model/account_invoice.py
deleted file mode 100644
index c60e86aa0..000000000
--- a/account_loan/model/account_invoice.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2018 Creu Blanca
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-
-from odoo import api, fields, models
-
-
-class AccountInvoice(models.Model):
- _inherit = "account.invoice"
-
- loan_line_id = fields.Many2one(
- "account.loan.line", readonly=True, ondelete="restrict",
- )
- loan_id = fields.Many2one(
- "account.loan", readonly=True, store=True, ondelete="restrict",
- )
-
- @api.multi
- def finalize_invoice_move_lines(self, move_lines):
- vals = super().finalize_invoice_move_lines(move_lines)
- if self.loan_line_id:
- ll = self.loan_line_id
- if ll.long_term_loan_account_id and ll.long_term_principal_amount != 0:
- vals.append(
- (
- 0,
- 0,
- {
- "account_id": ll.loan_id.short_term_loan_account_id.id,
- "credit": ll.long_term_principal_amount,
- "debit": 0,
- },
- )
- )
- vals.append(
- (
- 0,
- 0,
- {
- "account_id": ll.long_term_loan_account_id.id,
- "credit": 0,
- "debit": ll.long_term_principal_amount,
- },
- )
- )
- return vals
diff --git a/account_loan/model/account_loan.py b/account_loan/model/account_loan.py
index 5a4fe4fc0..6917549db 100644
--- a/account_loan/model/account_loan.py
+++ b/account_loan/model/account_loan.py
@@ -11,7 +11,7 @@ from odoo import api, fields, models
_logger = logging.getLogger(__name__)
try:
- import numpy
+ import numpy_financial
except (ImportError, IOError) as err:
_logger.debug(err)
@@ -96,7 +96,7 @@ class AccountLoan(models.Model):
help="Real rate that will be applied on each period",
)
rate_type = fields.Selection(
- [("napr", "Nominal APR"), ("ear", "EAR"), ("real", "Real rate"),],
+ [("napr", "Nominal APR"), ("ear", "EAR"), ("real", "Real rate")],
required=True,
help="Method of computation of the applied rate",
default="napr",
@@ -253,7 +253,7 @@ class AccountLoan(models.Model):
for record in self:
if record.loan_type == "fixed-annuity":
record.fixed_amount = -record.currency_id.round(
- numpy.pmt(
+ numpy_financial.pmt(
record.loan_rate() / 100,
record.fixed_periods,
record.fixed_loan_amount,
@@ -262,7 +262,7 @@ class AccountLoan(models.Model):
)
elif record.loan_type == "fixed-annuity-begin":
record.fixed_amount = -record.currency_id.round(
- numpy.pmt(
+ numpy_financial.pmt(
record.loan_rate() / 100,
record.fixed_periods,
record.fixed_loan_amount,
@@ -341,7 +341,6 @@ class AccountLoan(models.Model):
vals["name"] = self.get_default_name(vals)
return super().create(vals)
- @api.multi
def post(self):
self.ensure_one()
if not self.start_date:
@@ -349,11 +348,9 @@ class AccountLoan(models.Model):
self.compute_draft_lines()
self.write({"state": "posted"})
- @api.multi
def close(self):
self.write({"state": "closed"})
- @api.multi
def compute_lines(self):
self.ensure_one()
if self.state == "draft":
@@ -407,7 +404,6 @@ class AccountLoan(models.Model):
"rate": self.rate_period,
}
- @api.multi
def compute_draft_lines(self):
self.ensure_one()
self.fixed_periods = self.periods
@@ -431,7 +427,6 @@ class AccountLoan(models.Model):
if self.long_term_loan_account_id:
self.check_long_term_principal_amount()
- @api.multi
def view_account_moves(self):
self.ensure_one()
action = self.env.ref("account.action_move_line_form")
@@ -439,10 +434,9 @@ class AccountLoan(models.Model):
result["domain"] = [("loan_id", "=", self.id)]
return result
- @api.multi
def view_account_invoices(self):
self.ensure_one()
- action = self.env.ref("account.action_invoice_tree2")
+ action = self.env.ref("account.action_move_out_invoice_type")
result = action.read()[0]
result["domain"] = [("loan_id", "=", self.id), ("type", "=", "in_invoice")]
return result
@@ -471,6 +465,6 @@ class AccountLoan(models.Model):
[("state", "=", "posted"), ("is_leasing", "=", True)]
):
res += record.line_ids.filtered(
- lambda r: r.date <= date and not r.invoice_ids
+ lambda r: r.date <= date and not r.move_ids
).generate_invoice()
return res
diff --git a/account_loan/model/account_loan_line.py b/account_loan/model/account_loan_line.py
index 9ff568172..075340a30 100644
--- a/account_loan/model/account_loan_line.py
+++ b/account_loan/model/account_loan_line.py
@@ -8,7 +8,7 @@ from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
try:
- import numpy
+ import numpy_financial
except (ImportError, IOError) as err:
_logger.error(err)
@@ -90,7 +90,6 @@ class AccountLoanLine(models.Model):
)
move_ids = fields.One2many("account.move", inverse_name="loan_line_id",)
has_moves = fields.Boolean(compute="_compute_has_moves")
- invoice_ids = fields.One2many("account.invoice", inverse_name="loan_line_id",)
has_invoices = fields.Boolean(compute="_compute_has_invoices")
_sql_constraints = [
(
@@ -105,10 +104,10 @@ class AccountLoanLine(models.Model):
for record in self:
record.has_moves = bool(record.move_ids)
- @api.depends("invoice_ids")
+ @api.depends("move_ids")
def _compute_has_invoices(self):
for record in self:
- record.has_invoices = bool(record.invoice_ids)
+ record.has_invoices = bool(record.move_ids)
@api.depends("loan_id.name", "sequence")
def _compute_name(self):
@@ -146,7 +145,7 @@ class AccountLoanLine(models.Model):
return self.loan_id.fixed_amount
if self.loan_type == "fixed-annuity":
return self.currency_id.round(
- -numpy.pmt(
+ -numpy_financial.pmt(
self.loan_id.loan_rate() / 100,
self.loan_id.periods - self.sequence + 1,
self.pending_principal_amount,
@@ -157,7 +156,7 @@ class AccountLoanLine(models.Model):
return self.loan_id.fixed_amount
if self.loan_type == "fixed-annuity-begin":
return self.currency_id.round(
- -numpy.pmt(
+ -numpy_financial.pmt(
self.loan_id.loan_rate() / 100,
self.loan_id.periods - self.sequence + 1,
self.pending_principal_amount,
@@ -168,7 +167,7 @@ class AccountLoanLine(models.Model):
def check_amount(self):
"""Recompute amounts if the annuity has not been processed"""
- if self.move_ids or self.invoice_ids:
+ if self.move_ids:
raise UserError(
_("Amount cannot be recomputed if moves or invoices exists " "already")
)
@@ -192,7 +191,7 @@ class AccountLoanLine(models.Model):
def compute_interest(self):
if self.loan_type == "fixed-annuity-begin":
- return -numpy.ipmt(
+ return -numpy_financial.ipmt(
self.loan_id.loan_rate() / 100,
2,
self.loan_id.periods - self.sequence + 1,
@@ -202,7 +201,6 @@ class AccountLoanLine(models.Model):
)
return self.pending_principal_amount * self.loan_id.loan_rate() / 100
- @api.multi
def check_move_amount(self):
"""
Changes the amounts of the annuity once the move is posted
@@ -286,16 +284,12 @@ class AccountLoanLine(models.Model):
return vals
def invoice_vals(self):
- partner = self.loan_id.partner_id.with_context(
- force_company=self.loan_id.company_id.id
- )
return {
"loan_line_id": self.id,
"loan_id": self.loan_id.id,
"type": "in_invoice",
"partner_id": self.loan_id.partner_id.id,
- "date_invoice": self.date,
- "account_id": partner.property_account_payable_id.id,
+ "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()],
@@ -323,7 +317,6 @@ class AccountLoanLine(models.Model):
)
return vals
- @api.multi
def generate_move(self):
"""
Computes and post the moves of loans
@@ -341,29 +334,59 @@ class AccountLoanLine(models.Model):
res.append(move.id)
return res
- @api.multi
def generate_invoice(self):
"""
Computes invoices of leases
- :return: list of account.invoice generated
+ :return: list of account.move generated
"""
res = []
for record in self:
- if not record.invoice_ids:
+ if not record.move_ids:
if record.loan_id.line_ids.filtered(
- lambda r: r.date < record.date and not r.invoice_ids
+ lambda r: r.date < record.date and not r.move_ids
):
raise UserError(_("Some invoices must be created first"))
- invoice = self.env["account.invoice"].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._set_taxes()
- invoice.compute_taxes()
+ line.tax_ids = line._get_computed_taxes()
+ invoice.with_context(
+ check_move_validity=False
+ )._recompute_dynamic_lines(recompute_all_taxes=True)
+ invoice._check_balanced()
+ 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_invoice_open()
+ invoice.post()
return res
- @api.multi
+ 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,
+ },
+ ),
+ ]
+
def view_account_values(self):
"""Shows the invoice if it is a leasing or the move if it is a loan"""
self.ensure_one()
@@ -371,7 +394,6 @@ class AccountLoanLine(models.Model):
return self.view_account_invoices()
return self.view_account_moves()
- @api.multi
def view_process_values(self):
"""Computes the annuity and returns the result"""
self.ensure_one()
@@ -381,7 +403,6 @@ class AccountLoanLine(models.Model):
self.generate_move()
return self.view_account_values()
- @api.multi
def view_account_moves(self):
self.ensure_one()
action = self.env.ref("account.action_move_line_form")
@@ -397,18 +418,17 @@ class AccountLoanLine(models.Model):
result["res_id"] = self.move_ids.id
return result
- @api.multi
def view_account_invoices(self):
self.ensure_one()
- action = self.env.ref("account.action_invoice_tree2")
+ action = self.env.ref("account.action_move_out_invoice_type")
result = action.read()[0]
result["context"] = {
"default_loan_line_id": self.id,
"default_loan_id": self.loan_id.id,
}
result["domain"] = [("loan_line_id", "=", self.id), ("type", "=", "in_invoice")]
- if len(self.invoice_ids) == 1:
- res = self.env.ref("account.invoice.supplier.form", False)
+ if len(self.move_ids) == 1:
+ res = self.env.ref("account.view_move_form", False)
result["views"] = [(res and res.id or False, "form")]
- result["res_id"] = self.invoice_ids.id
+ result["res_id"] = self.move_ids.id
return result
diff --git a/account_loan/model/account_move.py b/account_loan/model/account_move.py
index 2cbb6e766..1691397fc 100644
--- a/account_loan/model/account_move.py
+++ b/account_loan/model/account_move.py
@@ -1,7 +1,7 @@
# Copyright 2018 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-from odoo import api, fields, models
+from odoo import fields, models
class AccountMove(models.Model):
@@ -14,11 +14,10 @@ class AccountMove(models.Model):
"account.loan", readonly=True, store=True, ondelete="restrict",
)
- @api.multi
- def post(self, invoice=False):
- res = super().post(invoice=invoice)
+ def post(self):
+ res = super().post()
for record in self:
- loan_line_id = record.loan_line_id or (invoice and invoice.loan_line_id)
+ loan_line_id = record.loan_line_id
if loan_line_id:
if not record.loan_line_id:
record.loan_line_id = loan_line_id
diff --git a/account_loan/static/description/index.html b/account_loan/static/description/index.html
index 16f54a526..604a55f20 100644
--- a/account_loan/static/description/index.html
+++ b/account_loan/static/description/index.html
@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

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.
@@ -420,7 +420,7 @@ leases before a selected date
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 smashing it by providing a detailed and welcomed
-feedback.
+feedback.
Do not contact contributors directly about support or help with technical issues.
@@ -446,7 +446,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
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.
+
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/tests/test_loan.py b/account_loan/tests/test_loan.py
index 0671c9ad1..3fbb15257 100644
--- a/account_loan/tests/test_loan.py
+++ b/account_loan/tests/test_loan.py
@@ -7,15 +7,16 @@ from dateutil.relativedelta import relativedelta
from odoo import fields
from odoo.exceptions import UserError
-from odoo.tests import TransactionCase
+from odoo.tests import TransactionCase, tagged
_logger = logging.getLogger(__name__)
try:
- import numpy
+ import numpy_financial
except (ImportError, IOError) as err:
_logger.error(err)
+@tagged("post_install", "-at_install")
class TestLoan(TransactionCase):
def setUp(self):
super().setUp()
@@ -108,7 +109,7 @@ class TestLoan(TransactionCase):
self.assertEqual(len(loan.line_ids), periods)
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertAlmostEqual(
- -numpy.pmt(1 / 100 / 12, 24, 10000), line.payment_amount, 2
+ -numpy_financial.pmt(1 / 100 / 12, 24, 10000), line.payment_amount, 2
)
self.assertEqual(line.long_term_principal_amount, 0)
loan.long_term_loan_account_id = self.lt_loan_account
@@ -120,14 +121,14 @@ class TestLoan(TransactionCase):
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertTrue(line)
self.assertFalse(line.move_ids)
- self.assertFalse(line.invoice_ids)
wzd = self.env["account.loan.generate.wizard"].create({})
action = wzd.run()
self.assertTrue(action)
self.assertFalse(wzd.run())
self.assertTrue(line.move_ids)
self.assertIn(line.move_ids.id, action["domain"][0][2])
- line.move_ids.post()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "posted")
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
{
@@ -139,15 +140,15 @@ class TestLoan(TransactionCase):
).run()
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
- {"loan_id": loan.id, "amount": amount, "fees": 100, "date": line.date,}
+ {"loan_id": loan.id, "amount": amount, "fees": 100, "date": line.date}
).run()
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
- {"loan_id": loan.id, "amount": 0, "fees": 100, "date": line.date,}
+ {"loan_id": loan.id, "amount": 0, "fees": 100, "date": line.date}
).run()
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
- {"loan_id": loan.id, "amount": -100, "fees": 100, "date": line.date,}
+ {"loan_id": loan.id, "amount": -100, "fees": 100, "date": line.date}
).run()
def test_fixed_annuity_begin_loan(self):
@@ -158,7 +159,9 @@ class TestLoan(TransactionCase):
self.assertEqual(len(loan.line_ids), periods)
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertAlmostEqual(
- -numpy.pmt(1 / 100 / 12, 24, 10000, when="begin"), line.payment_amount, 2
+ -numpy_financial.pmt(1 / 100 / 12, 24, 10000, when="begin"),
+ line.payment_amount,
+ 2,
)
self.assertEqual(line.long_term_principal_amount, 0)
loan.long_term_loan_account_id = self.lt_loan_account
@@ -170,25 +173,25 @@ class TestLoan(TransactionCase):
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertTrue(line)
self.assertFalse(line.move_ids)
- self.assertFalse(line.invoice_ids)
wzd = self.env["account.loan.generate.wizard"].create({})
action = wzd.run()
self.assertTrue(action)
self.assertFalse(wzd.run())
self.assertTrue(line.move_ids)
self.assertIn(line.move_ids.id, action["domain"][0][2])
- line.move_ids.post()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "posted")
loan.rate = 2
loan.compute_lines()
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertAlmostEqual(
- -numpy.pmt(1 / 100 / 12, periods, amount, when="begin"),
+ -numpy_financial.pmt(1 / 100 / 12, periods, amount, when="begin"),
line.payment_amount,
2,
)
line = loan.line_ids.filtered(lambda r: r.sequence == 2)
self.assertAlmostEqual(
- -numpy.pmt(
+ -numpy_financial.pmt(
2 / 100 / 12, periods - 1, line.pending_principal_amount, when="begin"
),
line.payment_amount,
@@ -206,7 +209,7 @@ class TestLoan(TransactionCase):
self.assertEqual(len(loan.line_ids), periods)
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertAlmostEqual(
- -numpy.pmt(1 / 100 / 12, 24, 10000), line.payment_amount, 2
+ -numpy_financial.pmt(1 / 100 / 12, 24, 10000), line.payment_amount, 2
)
self.assertEqual(line.long_term_principal_amount, 0)
loan.long_term_loan_account_id = self.lt_loan_account
@@ -218,23 +221,25 @@ class TestLoan(TransactionCase):
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertTrue(line)
self.assertFalse(line.move_ids)
- self.assertFalse(line.invoice_ids)
wzd = self.env["account.loan.generate.wizard"].create({})
action = wzd.run()
self.assertTrue(action)
self.assertFalse(wzd.run())
self.assertTrue(line.move_ids)
self.assertIn(line.move_ids.id, action["domain"][0][2])
- line.move_ids.post()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "posted")
loan.rate = 2
loan.compute_lines()
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
self.assertAlmostEqual(
- -numpy.pmt(1 / 100 / 12, periods, amount), line.payment_amount, 2
+ -numpy_financial.pmt(1 / 100 / 12, periods, amount), line.payment_amount, 2
)
line = loan.line_ids.filtered(lambda r: r.sequence == 2)
self.assertAlmostEqual(
- -numpy.pmt(2 / 100 / 12, periods - 1, line.pending_principal_amount),
+ -numpy_financial.pmt(
+ 2 / 100 / 12, periods - 1, line.pending_principal_amount
+ ),
line.payment_amount,
2,
)
@@ -242,7 +247,7 @@ class TestLoan(TransactionCase):
with self.assertRaises(UserError):
line.view_process_values()
- def test_fixed_principal_loan(self):
+ def test_fixed_principal_loan_leasing(self):
amount = 24000
periods = 24
loan = self.create_loan("fixed-principal", amount, 1, periods)
@@ -266,12 +271,18 @@ class TestLoan(TransactionCase):
self.assertFalse(line.has_moves)
action = (
self.env["account.loan.generate.wizard"]
- .create({"date": fields.date.today(), "loan_type": "leasing",})
+ .create(
+ {
+ "date": fields.date.today() + relativedelta(days=1),
+ "loan_type": "leasing",
+ }
+ )
.run()
)
self.assertTrue(line.has_invoices)
- self.assertFalse(line.has_moves)
- self.assertIn(line.invoice_ids.id, action["domain"][0][2])
+ self.assertTrue(line.has_moves)
+ self.assertIn(line.move_ids.id, action["domain"][0][2])
+ loan.refresh()
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
{
@@ -291,17 +302,18 @@ class TestLoan(TransactionCase):
+ relativedelta(months=-1),
}
).run()
- line.invoice_ids.action_invoice_open()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "draft")
self.assertTrue(line.has_moves)
+ line.move_ids.post()
+ self.assertEqual(line.move_ids.state, "posted")
self.assertIn(
line.move_ids.id,
self.env["account.move"].search(loan.view_account_moves()["domain"]).ids,
)
self.assertEqual(
- line.invoice_ids.id,
- self.env["account.invoice"]
- .search(loan.view_account_invoices()["domain"])
- .id,
+ line.move_ids.id,
+ self.env["account.move"].search(loan.view_account_invoices()["domain"]).id,
)
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
@@ -333,7 +345,7 @@ class TestLoan(TransactionCase):
with self.assertRaises(UserError):
line.view_process_values()
- def test_fixed_principal_loan_auto_post(self):
+ def test_fixed_principal_loan_auto_post_leasing(self):
amount = 24000
periods = 24
loan = self.create_loan("fixed-principal", amount, 1, periods)
@@ -355,7 +367,7 @@ class TestLoan(TransactionCase):
self.assertFalse(line.has_invoices)
self.assertFalse(line.has_moves)
self.env["account.loan.generate.wizard"].create(
- {"date": fields.date.today(), "loan_type": "leasing",}
+ {"date": fields.date.today(), "loan_type": "leasing"}
).run()
self.assertTrue(line.has_invoices)
self.assertTrue(line.has_moves)
@@ -383,9 +395,10 @@ class TestLoan(TransactionCase):
for line in loan.line_ids:
self.assertEqual(loan.state, "posted")
line.view_process_values()
- line.move_ids.post()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "posted")
self.assertEqual(loan.state, "closed")
-
+ loan.refresh()
self.assertEqual(loan.payment_amount - loan.interests_amount, amount)
self.assertEqual(loan.pending_principal_amount, 0)
@@ -396,7 +409,8 @@ class TestLoan(TransactionCase):
self.post(loan)
line = loan.line_ids.filtered(lambda r: r.sequence == 1)
line.view_process_values()
- line.move_ids.post()
+ self.assertTrue(line.move_ids)
+ self.assertEqual(line.move_ids.state, "posted")
pay = self.env["account.loan.pay.amount"].create(
{"loan_id": loan.id, "amount": 0, "fees": 100, "date": line.date}
)
diff --git a/account_loan/wizard/account_loan_generate_entries.py b/account_loan/wizard/account_loan_generate_entries.py
index c749a18af..e34208867 100644
--- a/account_loan/wizard/account_loan_generate_entries.py
+++ b/account_loan/wizard/account_loan_generate_entries.py
@@ -1,6 +1,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import api, fields, models
+from odoo import fields, models
class AccountLoanGenerateWizard(models.TransientModel):
@@ -15,12 +15,12 @@ class AccountLoanGenerateWizard(models.TransientModel):
default=fields.Date.context_today,
)
loan_type = fields.Selection(
- [("leasing", "Leasings"), ("loan", "Loans"),], required=True, default="loan"
+ [("leasing", "Leasings"), ("loan", "Loans")], required=True, default="loan"
)
def run_leasing(self):
created_ids = self.env["account.loan"].generate_leasing_entries(self.date)
- action = self.env.ref("account.action_invoice_tree2")
+ action = self.env.ref("account.action_move_out_invoice_type")
result = action.read()[0]
if len(created_ids) == 0:
return
@@ -36,7 +36,6 @@ class AccountLoanGenerateWizard(models.TransientModel):
result["domain"] = [("id", "in", created_ids)]
return result
- @api.multi
def run(self):
self.ensure_one()
if self.loan_type == "leasing":
diff --git a/account_loan/wizard/account_loan_pay_amount.py b/account_loan/wizard/account_loan_pay_amount.py
index 802f0f120..91089398d 100644
--- a/account_loan/wizard/account_loan_pay_amount.py
+++ b/account_loan/wizard/account_loan_pay_amount.py
@@ -24,9 +24,9 @@ class AccountLoan(models.TransientModel):
def _onchange_cancel_loan(self):
if self.cancel_loan:
self.amount = max(
- self.loan_id.line_ids.filtered(
- lambda r: not r.move_ids and not r.invoice_ids
- ).mapped("pending_principal_amount")
+ self.loan_id.line_ids.filtered(lambda r: not r.move_ids).mapped(
+ "pending_principal_amount"
+ )
)
def new_line_vals(self, sequence):
@@ -39,16 +39,15 @@ class AccountLoan(models.TransientModel):
"date": self.date,
}
- @api.multi
def run(self):
self.ensure_one()
if self.loan_id.is_leasing:
if self.loan_id.line_ids.filtered(
- lambda r: r.date < self.date and not r.invoice_ids
+ lambda r: r.date <= self.date and not r.move_ids
):
raise UserError(_("Some invoices are not created"))
if self.loan_id.line_ids.filtered(
- lambda r: r.date > self.date and r.invoice_ids
+ lambda r: r.date > self.date and r.move_ids
):
raise UserError(_("Some future invoices already exists"))
if self.loan_id.line_ids.filtered(
@@ -63,6 +62,7 @@ class AccountLoan(models.TransientModel):
sequence = min(lines.mapped("sequence"))
for line in lines:
line.sequence += 1
+ line.flush()
old_line = lines.filtered(lambda r: r.sequence == sequence + 1)
pending = old_line.pending_principal_amount
if self.loan_id.currency_id.compare_amounts(self.amount, pending) == 1:
diff --git a/account_loan/wizard/account_loan_post.py b/account_loan/wizard/account_loan_post.py
index fc39d6cfb..c7ceb7f56 100644
--- a/account_loan/wizard/account_loan_post.py
+++ b/account_loan/wizard/account_loan_post.py
@@ -10,13 +10,13 @@ class AccountLoanPost(models.TransientModel):
@api.model
def _default_journal_id(self):
- loan_id = self._context.get("default_loan_id")
+ loan_id = self.env.context.get("default_loan_id")
if loan_id:
return self.env["account.loan"].browse(loan_id).journal_id.id
@api.model
def _default_account_id(self):
- loan_id = self._context.get("default_loan_id")
+ loan_id = self.env.context.get("default_loan_id")
if loan_id:
loan = self.env["account.loan"].browse(loan_id)
if loan.is_leasing:
@@ -28,10 +28,10 @@ class AccountLoanPost(models.TransientModel):
loan_id = fields.Many2one("account.loan", required=True, readonly=True,)
journal_id = fields.Many2one(
- "account.journal", required=True, default=_default_journal_id
+ "account.journal", required=True, default=lambda r: r._default_journal_id()
)
account_id = fields.Many2one(
- "account.account", required=True, default=_default_account_id
+ "account.account", required=True, default=lambda r: r._default_account_id()
)
def move_line_vals(self):
@@ -82,7 +82,6 @@ class AccountLoanPost(models.TransientModel):
"line_ids": [(0, 0, vals) for vals in self.move_line_vals()],
}
- @api.multi
def run(self):
self.ensure_one()
if self.loan_id.state != "draft":