[MIG] account_loan: Migration to 13.0

Co-authored-by: Enric Tobella <etobella@creublanca.es>

[UPD] Update account_loan.pot

[UPD] README.rst
This commit is contained in:
Alba Riera
2021-02-23 12:15:36 +01:00
committed by Víctor Martínez
parent f91d710bc5
commit 35efc16a0e
14 changed files with 219 additions and 213 deletions

View File

@@ -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 <https://github.com/OCA/account-financial-tools/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 <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_loan%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_loan%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
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 <https://github.com/OCA/account-financial-tools/tree/12.0/account_loan>`_ project on GitHub.
This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/13.0/account_loan>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@@ -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"]},
}

View File

@@ -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 ""

View File

@@ -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""",
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/12.0/account_loan"><img alt="OCA/account-financial-tools" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/account-financial-tools-12-0/account-financial-tools-12-0-account_loan"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/92/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/13.0/account_loan"><img alt="OCA/account-financial-tools" src="https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/account-financial-tools-13-0/account-financial-tools-13-0-account_loan"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/92/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>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.</p>
@@ -420,7 +420,7 @@ leases before a selected date</li>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/account-financial-tools/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_loan%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<a class="reference external" href="https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_loan%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
@@ -446,7 +446,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/12.0/account_loan">OCA/account-financial-tools</a> project on GitHub.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/13.0/account_loan">OCA/account-financial-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>

View File

@@ -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}
)

View File

@@ -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":

View File

@@ -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:

View File

@@ -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":