2
0

[MIG] account_loan: Mirgation to 16.0

This commit is contained in:
Enric Tobella 2023-09-15 10:04:47 +02:00
parent e5e38a86e0
commit bf6075876f
20 changed files with 221 additions and 180 deletions

View File

@ -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 <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 to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_loan%0Aversion:%2014.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:%2016.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.
@ -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 <https://github.com/OCA/account-financial-tools/tree/14.0/account_loan>`_ project on GitHub.
.. |maintainer-etobella| image:: https://github.com/etobella.png?size=40px
:target: https://github.com/etobella
:alt: etobella
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-etobella|
This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/16.0/account_loan>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_account_loan_manager account.loan model_account_loan account.group_account_manager 1 1 1 1
4 access_account_loan_line account.loan.line model_account_loan_line account.group_account_user 1 0 0 0
5 access_account_loan_line_manager account.loan.line model_account_loan_line account.group_account_manager 1 1 1 1
6 access_account_loan_generate_wizard access_account_loan_generate_wizard model_account_loan_generate_wizard account.group_account_user account.group_account_manager 1 0 1 0 1 0 1
7 access_account_loan_pay_amount access_account_loan_pay_amount model_account_loan_pay_amount account.group_account_user account.group_account_manager 1 0 1 0 1 0 1
8 access_account_loan_post access_account_loan_post model_account_loan_post account.group_account_user account.group_account_manager 1 0 1 0 1 0 1
access_account_loan_post_manager access_account_loan_post_manager model_account_loan_post account.group_account_manager 1 1 1 1

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<meta name="generator" content="Docutils: http://docutils.sourceforge.net/" />
<title>Account Loan management</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
@ -367,9 +367,9 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ede8542c931551ec36dabc09621d29b3bcb54586fcad8fd3c4509b95ce8198bf
!! source digest: sha256:c9f87eb07ebda20ab00e0446ae5e5908b6a64086fd868f2bfc58e4e9f7dc68b0
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" 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 image-reference" 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 image-reference" href="https://github.com/OCA/account-financial-tools/tree/14.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 image-reference" href="https://translation.odoo-community.org/projects/account-financial-tools-14-0/account-financial-tools-14-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 image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&amp;target_branch=14.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-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/16.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-16-0/account-financial-tools-16-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://runboat.odoo-community.org/builds?repo=OCA/account-financial-tools&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-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>
@ -388,18 +388,22 @@ Moreover, you can check the pending amount to be paid and reduce the debt.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li>
<li><a class="reference internal" href="#changelog" id="id3">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id4">16.0.1.0.0</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id8">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id9">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<h1><a class="toc-backref" href="#id2">Usage</a></h1>
<p>To use this module, you need to:</p>
<ol class="arabic simple">
<li>Go to <cite>Invoicing / Accounting &gt; Adviser &gt; Loans</cite></li>
@ -417,24 +421,31 @@ leases before a selected date</li>
</ul>
<a class="reference external image-reference" href="https://runbot.odoo-community.org/runbot/92/12.0"><img alt="Try me on Runbot" src="https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas" /></a>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id3">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id4">16.0.1.0.0</a></h2>
<p>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.</p>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#id5">Bug Tracker</a></h1>
<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 to smash 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:%2014.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:%2016.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">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<h1><a class="toc-backref" href="#id6">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<h2><a class="toc-backref" href="#id7">Authors</a></h2>
<ul class="simple">
<li>Creu Blanca</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<h2><a class="toc-backref" href="#id8">Contributors</a></h2>
<ul class="simple">
<li>Enric Tobella &lt;<a class="reference external" href="mailto:etobella&#64;creublanca.es">etobella&#64;creublanca.es</a>&gt;</li>
<li>Bhavesh Odedra &lt;<a class="reference external" href="mailto:bodedra&#64;opensourceintegrators.com">bodedra&#64;opensourceintegrators.com</a>&gt;</li>
@ -442,13 +453,15 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<h2><a class="toc-backref" href="#id9">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<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/14.0/account_loan">OCA/account-financial-tools</a> project on GitHub.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external" href="https://github.com/etobella"><img alt="etobella" src="https://github.com/etobella.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/account-financial-tools/tree/16.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

@ -18,42 +18,37 @@ except (ImportError, IOError) as err:
@tagged("post_install", "-at_install")
class TestLoan(TransactionCase):
def setUp(self):
super().setUp()
self.company = self.browse_ref("base.main_company")
self.company_02 = self.env["res.company"].create({"name": "Auxiliar company"})
self.journal = self.env["account.journal"].create(
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.company = cls.env.ref("base.main_company")
cls.company_02 = cls.env["res.company"].create({"name": "Auxiliar company"})
cls.journal = cls.env["account.journal"].create(
{
"company_id": self.company.id,
"company_id": cls.company.id,
"type": "purchase",
"name": "Debts",
"code": "DBT",
}
)
self.loan_account = self.create_account(
cls.loan_account = cls.create_account(
"DEP",
"depreciation",
self.browse_ref("account.data_account_type_current_liabilities").id,
"liability_current",
)
self.payable_account = self.create_account(
"PAY", "payable", self.browse_ref("account.data_account_type_payable").id
)
self.asset_account = self.create_account(
"ASSET", "asset", self.browse_ref("account.data_account_type_payable").id
)
self.interests_account = self.create_account(
"FEE", "Fees", self.browse_ref("account.data_account_type_expenses").id
)
self.lt_loan_account = self.create_account(
cls.payable_account = cls.create_account("PAY", "payable", "liability_payable")
cls.asset_account = cls.create_account("ASSET", "asset", "liability_payable")
cls.interests_account = cls.create_account("FEE", "Fees", "expense")
cls.lt_loan_account = cls.create_account(
"LTD",
"Long term depreciation",
self.browse_ref("account.data_account_type_non_current_liabilities").id,
"liability_non_current",
)
self.partner = self.env["res.partner"].create({"name": "Bank"})
self.product = self.env["product.product"].create(
cls.partner = cls.env["res.partner"].create({"name": "Bank"})
cls.product = cls.env["product.product"].create(
{"name": "Payment", "type": "service"}
)
self.interests_product = self.env["product.product"].create(
cls.interests_product = cls.env["product.product"].create(
{"name": "Bank fee", "type": "service"}
)
@ -281,8 +276,10 @@ class TestLoan(TransactionCase):
)
self.assertTrue(line.has_invoices)
self.assertTrue(line.has_moves)
self.assertIn(line.move_ids.id, action["domain"][0][2])
loan.refresh()
self.assertEqual(
line.move_ids, self.env[action["res_model"]].search(action["domain"])
)
loan.invalidate_recordset()
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
{
@ -303,18 +300,22 @@ class TestLoan(TransactionCase):
}
).run()
self.assertTrue(line.move_ids)
self.assertEqual(line.move_ids.state, "draft")
self.assertTrue(line.move_ids.filtered(lambda r: r.is_invoice()))
self.assertTrue(line.move_ids.filtered(lambda r: not r.is_invoice()))
self.assertTrue(all([m.state == "draft" for m in line.move_ids]))
self.assertTrue(line.has_moves)
line.move_ids.action_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.move_ids.id,
self.env["account.move"].search(loan.view_account_invoices()["domain"]).id,
)
self.assertTrue(all([m.state == "posted" for m in line.move_ids]))
for move in line.move_ids:
self.assertIn(
move,
self.env["account.move"].search(loan.view_account_moves()["domain"]),
)
for move in line.move_ids.filtered(lambda r: r.is_invoice()):
self.assertIn(
move,
self.env["account.move"].search(loan.view_account_invoices()["domain"]),
)
with self.assertRaises(UserError):
self.env["account.loan.pay.amount"].create(
{
@ -398,7 +399,7 @@ class TestLoan(TransactionCase):
self.assertTrue(line.move_ids)
self.assertEqual(line.move_ids.state, "posted")
self.assertEqual(loan.state, "closed")
loan.refresh()
loan.invalidate_recordset()
self.assertEqual(loan.payment_amount - loan.interests_amount, amount)
self.assertEqual(loan.pending_principal_amount, 0)
@ -432,13 +433,14 @@ class TestLoan(TransactionCase):
with self.assertRaises(UserError):
post.run()
def create_account(self, code, name, type_id):
return self.env["account.account"].create(
@classmethod
def create_account(cls, code, name, account_type):
return cls.env["account.account"].create(
{
"company_id": self.company.id,
"company_id": cls.company.id,
"name": name,
"code": code,
"user_type_id": type_id,
"account_type": account_type,
"reconcile": True,
}
)

View File

@ -7,7 +7,7 @@
<field name="name">account.loan.tree</field>
<field name="model">account.loan</field>
<field name="arch" type="xml">
<tree string="Loans">
<tree>
<field name="name" />
<field name="company_id" />
<field name="is_leasing" />
@ -22,7 +22,7 @@
<field name="name">account.loan.form</field>
<field name="model">account.loan</field>
<field name="arch" type="xml">
<form string="Loan">
<form>
<header>
<button name="compute_lines" type="object" string="Compute items" />
<button
@ -30,11 +30,12 @@
states="draft"
type="action"
string="Post"
groups="account.group_account_manager"
/>
<field name="state" widget="statusbar" />
</header>
<sheet>
<div class="oe_button_box">
<div name="button_box" class="oe_button_box">
<button
name="view_account_moves"
class="oe_stat_button"
@ -58,6 +59,7 @@
attrs="{'invisible': [('state', '!=', 'posted')]}"
type="action"
string="Pay amount"
groups="account.group_account_manager"
/>
</div>
<h1>
@ -153,7 +155,7 @@
<field name="name">account.loan.line.tree</field>
<field name="model">account.loan.line</field>
<field name="arch" type="xml">
<tree string="Loan items" create="0">
<tree create="0">
<field name="sequence" />
<field name="date" />
<field name="rate" />

View File

@ -18,18 +18,18 @@ class AccountLoanGenerateWizard(models.TransientModel):
[("leasing", "Leasings"), ("loan", "Loans")], required=True, default="loan"
)
def run_leasing(self):
created_ids = self.env["account.loan"].generate_leasing_entries(self.date)
def _run_leasing(self):
created_ids = self.env["account.loan"]._generate_leasing_entries(self.date)
result = self.env["ir.actions.act_window"]._for_xml_id(
"account.action_move_out_invoice_type"
)
if len(created_ids) == 0:
return
result["domain"] = [("id", "in", created_ids), ("type", "=", "in_invoice")]
result["domain"] = [("id", "in", created_ids)]
return result
def run_loan(self):
created_ids = self.env["account.loan"].generate_loan_entries(self.date)
def _run_loan(self):
created_ids = self.env["account.loan"]._generate_loan_entries(self.date)
result = self.env["ir.actions.act_window"]._for_xml_id(
"account.action_move_line_form"
)
@ -41,5 +41,5 @@ class AccountLoanGenerateWizard(models.TransientModel):
def run(self):
self.ensure_one()
if self.loan_type == "leasing":
return self.run_leasing()
return self.run_loan()
return self._run_leasing()
return self._run_loan()

View File

@ -37,6 +37,6 @@
id="account_loan_generate_wizard_menu"
parent="account.menu_finance_entries_generate_entries"
sequence="111"
groups="base.group_no_one"
groups="account.group_account_manager"
/>
</odoo>

View File

@ -69,7 +69,7 @@ class AccountLoan(models.TransientModel):
sequence = min(lines.mapped("sequence"))
for line in lines:
line.sequence += 1
line.flush()
line.flush_recordset()
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:
@ -91,10 +91,10 @@ class AccountLoan(models.TransientModel):
line.pending_principal_amount = amount
if line.sequence != sequence:
line.rate = self.loan_id.rate_period
line.check_amount()
line._check_amount()
amount -= line.payment_amount - line.interests_amount
if self.loan_id.long_term_loan_account_id:
self.loan_id.check_long_term_principal_amount()
self.loan_id._check_long_term_principal_amount()
if self.loan_id.currency_id.compare_amounts(pending, self.amount) == 0:
self.loan_id.write({"state": "cancelled"})
return new_line.view_process_values()

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 Command, _, api, fields, models
from odoo.exceptions import UserError
@ -81,7 +81,7 @@ class AccountLoanPost(models.TransientModel):
"date": self.loan_id.start_date,
"ref": self.loan_id.name,
"journal_id": self.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 run(self):