2
0

[16.0][MIG] account_spread_cost_revenue

This commit is contained in:
Andrea Stirpe 2023-10-10 11:12:05 +02:00
parent e2ab9e5fdb
commit 0698663e48
22 changed files with 371 additions and 340 deletions

View File

@ -2,10 +2,13 @@
Cost-Revenue Spread
===================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:560d87ede92fd18ca4a929595b6a9fd9f558f6b577e8c9bad1f8e7236ad4175d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
@ -14,16 +17,16 @@ Cost-Revenue Spread
: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_spread_cost_revenue
:target: https://github.com/OCA/account-financial-tools/tree/16.0/account_spread_cost_revenue
: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_spread_cost_revenue
:target: https://translation.odoo-community.org/projects/account-financial-tools-16-0/account-financial-tools-16-0-account_spread_cost_revenue
: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/14.0
:alt: Try me on Runbot
.. |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=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
|badge1| |badge2| |badge3| |badge4| |badge5|
Allows to spread costs or revenues over a customizable periods, to even out cost or invoice spikes.
@ -67,7 +70,7 @@ Usage
Define Spread Costs/Revenues Board
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Under Invoicing -> Adviser -> Accounting Entries -> Spread Costs/Revenues, create a new spread board.
Under Invoicing -> Accounting -> Journals -> Spread Costs/Revenues, create a new spread board.
Complete the definition of the spreading criteria, by setting the the fields:
@ -79,17 +82,17 @@ Complete the definition of the spreading criteria, by setting the the fields:
* *Start date*
* *Journal*
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/spread.png
:alt: Create a new spread board
Click on the button on the top-left to calculate the spread lines.
Click on the "Recalculate unposted lines" button on the top-left to calculate the spread lines.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/create_spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/create_spread.png
:alt: The spreading board is defined
A cron job will automatically create the accounting moves for all the lines having date previous that the current day (today).
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/update_spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/update_spread.png
:alt: The spreading board is updated by the cron job
By default, the status of the created accounting moves is posted.
@ -104,7 +107,7 @@ Link Invoice to Spread Costs/Revenues Board
Create an invoice or vendor bill in draft. On its lines, the spreading right-arrow icon are displayed in dark-grey color.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_1.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_1.png
:alt: On the invoice line the spreading icon is displayed
Click on the spreading right-arrow icon. A wizard prompts to enter a *Spread Action Type*:
@ -119,11 +122,11 @@ the selected Spread Board will be automatically displayed.
Go back to the draft invoice/bill. The spreading functionality is now enabled on the invoice line:
the spreading right-arrow icon is now displayed in green color.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_2.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_2.png
:alt: On the invoice line the spreading icon is displayed in green color
Validate the invoice/bill. Click on the spreading (green) right-arrow icon to open the spread board, then click
on the smart button *Reconciled entries*: the moves of the spread lines are reconciled with the move of the invoice line.
on the smart button *Posted entries* to see the moves of the spread lines together with the move of the invoice line.
In case the Subtotal Price of the invoice line is different than the *Estimated Amount* of the spread board, the spread
lines (not yet posted) will be recalculated when validating the invoice/bill.
@ -181,8 +184,8 @@ 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_spread_cost_revenue%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
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_spread_cost_revenue%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.
@ -199,6 +202,7 @@ Contributors
* Andrea Stirpe <a.stirpe@onestein.nl>
* Kitti U. <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@ecosoft.co.th>
Other credits
~~~~~~~~~~~~~
@ -220,14 +224,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.
.. |maintainer-astirpe| image:: https://github.com/astirpe.png?size=40px
:target: https://github.com/astirpe
:alt: astirpe
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-astirpe|
This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/14.0/account_spread_cost_revenue>`_ project on GitHub.
This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/16.0/account_spread_cost_revenue>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -4,20 +4,13 @@
{
"name": "Cost-Revenue Spread",
"summary": "Spread costs and revenues over a custom period",
"version": "15.0.1.0.0",
"version": "16.0.1.0.0",
"development_status": "Beta",
"author": "Onestein,Odoo Community Association (OCA)",
"maintainers": ["astirpe"],
"license": "AGPL-3",
"website": "https://github.com/OCA/account-financial-tools",
"category": "Accounting & Finance",
"depends": ["account"],
"assets": {
"web.assets_backend": [
"/account_spread_cost_revenue/static/src/scss/account_spread.scss",
"/account_spread_cost_revenue/static/src/js/account_spread.js",
],
},
"data": [
"security/ir.model.access.csv",
"security/account_spread_security.xml",

View File

@ -13,7 +13,7 @@ class AccountMove(models.Model):
res = super().action_post()
spreads = self.mapped("invoice_line_ids.spread_id")
spreads.compute_spread_board()
# On posting of spread moves. Find their related spreads to creconcile
# On posting of spread moves. Find their related spreads to reconcile
move_spreads = self.env["account.spread"].search(
[("line_ids.move_id", "in", self.ids)]
)

View File

@ -129,8 +129,8 @@ class AccountMoveLine(models.Model):
if aline.account_id and iline.account_id != aline.account_id:
return False
if (
aline.analytic_account_id
and iline.account_analytic_id != aline.analytic_account_id
aline.analytic_distribution
and iline.analytic_distribution != aline.analytic_distribution
):
return False
return True

View File

@ -3,7 +3,6 @@
import calendar
import time
from datetime import timedelta
from dateutil.relativedelta import relativedelta
@ -15,7 +14,8 @@ from odoo.tools import float_is_zero
class AccountSpread(models.Model):
_name = "account.spread"
_description = "Account Spread"
_inherit = ["mail.thread"]
_inherit = ["mail.thread", "analytic.mixin"]
_check_company_auto = True
name = fields.Char(required=True)
template_id = fields.Many2one("account.spread.template", string="Spread Template")
@ -96,8 +96,15 @@ class AccountSpread(models.Model):
"account.journal",
compute="_compute_journal_id",
readonly=False,
precompute=True,
store=True,
required=True,
check_company=True,
domain="[('id', 'in', suitable_journal_ids)]",
)
suitable_journal_ids = fields.Many2many(
"account.journal",
compute="_compute_suitable_journal_ids",
)
invoice_line_ids = fields.One2many(
"account.move.line", "spread_id", copy=False, string="Invoice Lines"
@ -123,10 +130,6 @@ class AccountSpread(models.Model):
required=True,
default=lambda self: self.env.company.currency_id.id,
)
account_analytic_id = fields.Many2one(
"account.analytic.account", string="Analytic Account"
)
analytic_tag_ids = fields.Many2many("account.analytic.tag", string="Analytic Tags")
move_line_auto_post = fields.Boolean("Auto-post lines", default=True)
display_create_all_moves = fields.Boolean(
compute="_compute_display_create_all_moves",
@ -155,6 +158,12 @@ class AccountSpread(models.Model):
res["journal_id"] = default_journal.id
return res
@api.depends("company_id")
def _compute_suitable_journal_ids(self):
for spread in self:
domain = [("company_id", "=", spread.company_id.id)]
spread.suitable_journal_ids = self.env["account.journal"].search(domain)
@api.depends("invoice_type")
def _compute_spread_type(self):
for spread in self:
@ -248,6 +257,8 @@ class AccountSpread(models.Model):
self.period_type = self.template_id.period_type
if self.template_id.start_date:
self.spread_date = self.template_id.start_date
if self.template_id.analytic_distribution:
self.analytic_distribution = self.template_id.analytic_distribution
self.days_calc = self.template_id.days_calc
@api.depends("invoice_type", "company_id")
@ -444,7 +455,7 @@ class AccountSpread(models.Model):
spread_end_date = spread_start_date + relativedelta(years=number_of_periods)
# calculate by days and not first day of month should compute residual day only
if self.days_calc and spread_end_date.day != 1:
spread_end_date = spread_end_date - timedelta(days=1)
spread_end_date = spread_end_date - relativedelta(days=1)
else:
spread_end_date = self._get_last_day_of_month(spread_end_date)
return spread_end_date
@ -564,6 +575,8 @@ class AccountSpread(models.Model):
if mls_to_reconcile:
do_reconcile = mls_to_reconcile + self.invoice_line_id
do_reconcile.remove_move_reconcile()
for line in do_reconcile:
line.reconciled = False
# ensure to reconcile only posted items
do_reconcile = do_reconcile.filtered(lambda l: l.move_id.state == "posted")
do_reconcile._check_spread_reconcile_validity()
@ -588,12 +601,13 @@ class AccountSpread(models.Model):
spread.is_debit_account_deprecated = spread.debit_account_id.deprecated
spread.is_credit_account_deprecated = spread.credit_account_id.deprecated
def open_reconcile_view(self):
def open_posted_view(self):
action_name = "account_spread_cost_revenue.action_account_moves_all_spread"
[action] = self.env.ref(action_name).read()
action = self.env["ir.actions.act_window"]._for_xml_id(action_name)
action["domain"] = [("id", "in", [])]
spread_mls = self.line_ids.mapped("move_id.line_ids")
spread_mls = spread_mls.filtered(lambda m: m.reconciled)
if self.env.context.get("show_reconciled_only"):
spread_mls = spread_mls.filtered(lambda m: m.reconciled)
if spread_mls:
domain = [("id", "in", spread_mls.ids + [self.invoice_line_id.id])]
action["domain"] = domain

View File

@ -64,16 +64,10 @@ class AccountInvoiceSpreadLine(models.Model):
spread_date = self.env.context.get("spread_date") or self.date
spread = self.spread_id
analytic = spread.account_analytic_id
analytic_tags = []
if self.env["account.analytic.tag"].check_access_rights(
"read", raise_exception=False
):
analytic_tags = [(6, 0, spread.analytic_tag_ids.ids)]
analytic_distribution = spread.analytic_distribution
company_currency = spread.company_id.currency_id
current_currency = spread.currency_id
not_same_curr = company_currency != current_currency
amount = current_currency._convert(
self.amount, company_currency, spread.company_id, spread_date
)
@ -92,10 +86,9 @@ class AccountInvoiceSpreadLine(models.Model):
"debit": amount if amount > 0.0 else 0.0,
"credit": -amount if amount < 0.0 else 0.0,
"partner_id": self.spread_id.invoice_id.partner_id.id,
"analytic_account_id": analytic.id,
"analytic_tag_ids": analytic_tags,
"currency_id": not_same_curr and current_currency.id or False,
"amount_currency": not_same_curr and -1.0 * self.amount or 0.0,
"journal_id": self.spread_id.journal_id.id,
"analytic_distribution": analytic_distribution,
"date": self.date,
},
),
(
@ -109,10 +102,9 @@ class AccountInvoiceSpreadLine(models.Model):
"credit": amount if amount > 0.0 else 0.0,
"debit": -amount if amount < 0.0 else 0.0,
"partner_id": self.spread_id.invoice_id.partner_id.id,
"analytic_account_id": analytic.id,
"analytic_tag_ids": analytic_tags,
"currency_id": not_same_curr and current_currency.id or False,
"amount_currency": not_same_curr and self.amount or 0.0,
"journal_id": self.spread_id.journal_id.id,
"analytic_distribution": analytic_distribution,
"date": self.date,
},
),
]

View File

@ -7,6 +7,7 @@ from odoo.exceptions import UserError
class AccountSpreadTemplate(models.Model):
_name = "account.spread.template"
_inherit = "analytic.mixin"
_description = "Account Spread Template"
name = fields.Char(required=True)
@ -147,34 +148,10 @@ class AccountSpreadTemplate(models.Model):
spread_vals["invoice_type"] = invoice_type
return spread_vals
@api.constrains("auto_spread_ids", "auto_spread")
def _check_auto_spread_ids_unique(self):
query = """
select product_id, account_id, analytic_account_id
from (
select product_id, account_id, analytic_account_id, count(*)
from account_spread_template_auto a
join account_spread_template b on a.template_id = b.id
where b.auto_spread = true and b.id in %s
group by product_id, account_id, analytic_account_id
) x where x.count > 1 """
self._cr.execute(query, [self._ids])
results = []
for res in self._cr.fetchall():
product = self.env["product.product"].browse(res[0])
account = self.env["account.account"].browse(res[1])
analytic = self.env["account.analytic.account"].browse(res[2])
results.append(
"{} / {} / {}".format(product.name, account.name, analytic.name)
)
if results:
raise UserError(
_("Followings are duplicated combinations,\n\n%s") % "\n".join(results)
)
class AccountSpreadTemplateAuto(models.Model):
_name = "account.spread.template.auto"
_inherit = "analytic.mixin"
_description = "Auto create spread, based on product/account/analytic"
template_id = fields.Many2one(
@ -200,7 +177,3 @@ class AccountSpreadTemplateAuto(models.Model):
comodel_name="account.account",
string="Account",
)
analytic_account_id = fields.Many2one(
comodel_name="account.analytic.account",
string="Analytic",
)

View File

@ -1,7 +1,7 @@
Define Spread Costs/Revenues Board
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Under Invoicing -> Accounting -> Miscellaneous -> Spread Costs/Revenues, create a new spread board.
Under Invoicing -> Accounting -> Journals -> Spread Costs/Revenues, create a new spread board.
Complete the definition of the spreading criteria, by setting the the fields:
@ -13,17 +13,17 @@ Complete the definition of the spreading criteria, by setting the the fields:
* *Start date*
* *Journal*
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/spread.png
:alt: Create a new spread board
Click on the "Recalculate unposted lines" button on the top-left to calculate the spread lines.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/create_spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/create_spread.png
:alt: The spreading board is defined
A cron job will automatically create the accounting moves for all the lines having date previous that the current day (today).
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/update_spread.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/update_spread.png
:alt: The spreading board is updated by the cron job
By default, the status of the created accounting moves is posted.
@ -38,7 +38,7 @@ Link Invoice to Spread Costs/Revenues Board
Create an invoice or vendor bill in draft. On its lines, the spreading right-arrow icon are displayed in dark-grey color.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_1.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_1.png
:alt: On the invoice line the spreading icon is displayed
Click on the spreading right-arrow icon. A wizard prompts to enter a *Spread Action Type*:
@ -53,11 +53,11 @@ the selected Spread Board will be automatically displayed.
Go back to the draft invoice/bill. The spreading functionality is now enabled on the invoice line:
the spreading right-arrow icon is now displayed in green color.
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_2.png
.. figure:: https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_2.png
:alt: On the invoice line the spreading icon is displayed in green color
Validate the invoice/bill. Click on the spreading (green) right-arrow icon to open the spread board, then click
on the smart button *Reconciled entries*: the moves of the spread lines are reconciled with the move of the invoice line.
on the smart button *Posted entries* to see the moves of the spread lines together with the move of the invoice line.
In case the Subtotal Price of the invoice line is different than the *Estimated Amount* of the spread board, the spread
lines (not yet posted) will be recalculated when validating the invoice/bill.

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 0.15.1: http://docutils.sourceforge.net/" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Cost-Revenue Spread</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
@ -366,39 +366,41 @@ ul.auto-toc {
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:560d87ede92fd18ca4a929595b6a9fd9f558f6b577e8c9bad1f8e7236ad4175d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/14.0/account_spread_cost_revenue"><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-14-0/account-financial-tools-14-0-account_spread_cost_revenue"><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/14.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 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/16.0/account_spread_cost_revenue"><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-16-0/account-financial-tools-16-0-account_spread_cost_revenue"><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=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>Allows to spread costs or revenues over a customizable periods, to even out cost or invoice spikes.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id7">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="id8">Usage</a><ul>
<li><a class="reference internal" href="#define-spread-costs-revenues-board" id="id9">Define Spread Costs/Revenues Board</a></li>
<li><a class="reference internal" href="#link-invoice-to-spread-costs-revenues-board" id="id10">Link Invoice to Spread Costs/Revenues Board</a></li>
<li><a class="reference internal" href="#define-spread-costs-revenues-template" id="id11">Define Spread Costs/Revenues Template</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a><ul>
<li><a class="reference internal" href="#define-spread-costs-revenues-board" id="toc-entry-3">Define Spread Costs/Revenues Board</a></li>
<li><a class="reference internal" href="#link-invoice-to-spread-costs-revenues-board" id="toc-entry-4">Link Invoice to Spread Costs/Revenues Board</a></li>
<li><a class="reference internal" href="#define-spread-costs-revenues-template" id="toc-entry-5">Define Spread Costs/Revenues Template</a></li>
</ul>
</li>
<li><a class="reference internal" href="#changelog" id="id12">Changelog</a><ul>
<li><a class="reference internal" href="#id1" id="id13">13.0.1.0.0</a></li>
<li><a class="reference internal" href="#id2" id="id14">12.0.2.0.0</a></li>
<li><a class="reference internal" href="#id3" id="id15">12.0.1.1.0</a></li>
<li><a class="reference internal" href="#id4" id="id16">12.0.1.0.0</a></li>
<li><a class="reference internal" href="#id5" id="id17">11.0.1.0.0</a></li>
<li><a class="reference internal" href="#changelog" id="toc-entry-6">Changelog</a><ul>
<li><a class="reference internal" href="#section-1" id="toc-entry-7">13.0.1.0.0</a></li>
<li><a class="reference internal" href="#section-2" id="toc-entry-8">12.0.2.0.0</a></li>
<li><a class="reference internal" href="#section-3" id="toc-entry-9">12.0.1.1.0</a></li>
<li><a class="reference internal" href="#section-4" id="toc-entry-10">12.0.1.0.0</a></li>
<li><a class="reference internal" href="#section-5" id="toc-entry-11">11.0.1.0.0</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="id18">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id19">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id20">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id21">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="id22">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="id23">Maintainers</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-12">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-13">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-14">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-15">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-16">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-17">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id7">Configuration</a></h1>
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>To be able to access the full spreading features, the user must belong to <em>Show Full Accounting Features</em> group.</p>
<p>On the form view of the company, in the <em>Account Spread</em> tab, you can configure
the journals in which the spread journal items will be generated by default:</p>
@ -422,10 +424,10 @@ enable/disable the automatic posting by the flag <em>Auto-post lines</em> presen
cron job to automatically archive the spreads when all lines are posted.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id8">Usage</a></h1>
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<div class="section" id="define-spread-costs-revenues-board">
<h2><a class="toc-backref" href="#id9">Define Spread Costs/Revenues Board</a></h2>
<p>Under Invoicing -&gt; Adviser -&gt; Accounting Entries -&gt; Spread Costs/Revenues, create a new spread board.</p>
<h2><a class="toc-backref" href="#toc-entry-3">Define Spread Costs/Revenues Board</a></h2>
<p>Under Invoicing -&gt; Accounting -&gt; Journals -&gt; Spread Costs/Revenues, create a new spread board.</p>
<p>Complete the definition of the spreading criteria, by setting the the fields:</p>
<ul class="simple">
<li><em>Debit Account</em></li>
@ -437,15 +439,15 @@ cron job to automatically archive the spreads when all lines are posted.</p>
<li><em>Journal</em></li>
</ul>
<div class="figure">
<img alt="Create a new spread board" src="https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/spread.png" />
<img alt="Create a new spread board" src="https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/spread.png" />
</div>
<p>Click on the button on the top-left to calculate the spread lines.</p>
<p>Click on the “Recalculate unposted lines” button on the top-left to calculate the spread lines.</p>
<div class="figure">
<img alt="The spreading board is defined" src="https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/create_spread.png" />
<img alt="The spreading board is defined" src="https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/create_spread.png" />
</div>
<p>A cron job will automatically create the accounting moves for all the lines having date previous that the current day (today).</p>
<div class="figure">
<img alt="The spreading board is updated by the cron job" src="https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/update_spread.png" />
<img alt="The spreading board is updated by the cron job" src="https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/update_spread.png" />
</div>
<p>By default, the status of the created accounting moves is posted.
To disable the automatic posting of the accounting moves, set the flag <em>Auto-post lines</em> to False.
@ -454,10 +456,10 @@ This flag is only available when the <em>Auto-post spread lines</em> option, pre
this will also reset all the journal entries previously created.</p>
</div>
<div class="section" id="link-invoice-to-spread-costs-revenues-board">
<h2><a class="toc-backref" href="#id10">Link Invoice to Spread Costs/Revenues Board</a></h2>
<h2><a class="toc-backref" href="#toc-entry-4">Link Invoice to Spread Costs/Revenues Board</a></h2>
<p>Create an invoice or vendor bill in draft. On its lines, the spreading right-arrow icon are displayed in dark-grey color.</p>
<div class="figure">
<img alt="On the invoice line the spreading icon is displayed" src="https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_1.png" />
<img alt="On the invoice line the spreading icon is displayed" src="https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_1.png" />
</div>
<p>Click on the spreading right-arrow icon. A wizard prompts to enter a <em>Spread Action Type</em>:</p>
<ul class="simple">
@ -470,15 +472,15 @@ the selected Spread Board will be automatically displayed.</p>
<p>Go back to the draft invoice/bill. The spreading functionality is now enabled on the invoice line:
the spreading right-arrow icon is now displayed in green color.</p>
<div class="figure">
<img alt="On the invoice line the spreading icon is displayed in green color" src="https://raw.githubusercontent.com/OCA/account-financial-tools/12.0/account_spread_cost_revenue/static/description/invoice_line_2.png" />
<img alt="On the invoice line the spreading icon is displayed in green color" src="https://raw.githubusercontent.com/OCA/account-financial-tools/16.0/account_spread_cost_revenue/static/description/invoice_line_2.png" />
</div>
<p>Validate the invoice/bill. Click on the spreading (green) right-arrow icon to open the spread board, then click
on the smart button <em>Reconciled entries</em>: the moves of the spread lines are reconciled with the move of the invoice line.</p>
on the smart button <em>Posted entries</em> to see the moves of the spread lines together with the move of the invoice line.</p>
<p>In case the Subtotal Price of the invoice line is different than the <em>Estimated Amount</em> of the spread board, the spread
lines (not yet posted) will be recalculated when validating the invoice/bill.</p>
</div>
<div class="section" id="define-spread-costs-revenues-template">
<h2><a class="toc-backref" href="#id11">Define Spread Costs/Revenues Template</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Define Spread Costs/Revenues Template</a></h2>
<p>Under Invoicing -&gt; Configuration -&gt; Accounting -&gt; Spread Templates, create a new spread template.</p>
<ul class="simple">
<li><em>Spread Type</em></li>
@ -493,34 +495,34 @@ This way the above fields will be copied to the Spread Board.</p>
</div>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#id12">Changelog</a></h1>
<div class="section" id="id1">
<h2><a class="toc-backref" href="#id13">13.0.1.0.0</a></h2>
<h1><a class="toc-backref" href="#toc-entry-6">Changelog</a></h1>
<div class="section" id="section-1">
<h2><a class="toc-backref" href="#toc-entry-7">13.0.1.0.0</a></h2>
<ul class="simple">
<li>[MIG] Port account_spread_cost_revenue to V13.</li>
</ul>
</div>
<div class="section" id="id2">
<h2><a class="toc-backref" href="#id14">12.0.2.0.0</a></h2>
<div class="section" id="section-2">
<h2><a class="toc-backref" href="#toc-entry-8">12.0.2.0.0</a></h2>
<ul class="simple">
<li>[ENH] In spread template, add option to auto create spread on invoice validation</li>
</ul>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id15">12.0.1.1.0</a></h2>
<div class="section" id="section-3">
<h2><a class="toc-backref" href="#toc-entry-9">12.0.1.1.0</a></h2>
<ul class="simple">
<li>[ENH] Add optional Expense/Revenue Account in Chart Template, which can be used
in place of account from invoice line to set Expense/Revenue account in the spread</li>
</ul>
</div>
<div class="section" id="id4">
<h2><a class="toc-backref" href="#id16">12.0.1.0.0</a></h2>
<div class="section" id="section-4">
<h2><a class="toc-backref" href="#toc-entry-10">12.0.1.0.0</a></h2>
<ul class="simple">
<li>[MIG] Port account_spread_cost_revenue to V12.</li>
</ul>
</div>
<div class="section" id="id5">
<h2><a class="toc-backref" href="#id17">11.0.1.0.0</a></h2>
<div class="section" id="section-5">
<h2><a class="toc-backref" href="#toc-entry-11">11.0.1.0.0</a></h2>
<ul class="simple">
<li>[ADD] Module account_spread_cost_revenue.
(<a class="reference external" href="https://github.com/OCA/account-financial-tools/pull/715">#715</a>)</li>
@ -528,44 +530,43 @@ in place of account from invoice line to set Expense/Revenue account in the spre
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id18">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#toc-entry-12">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 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_spread_cost_revenue%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
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_spread_cost_revenue%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="#id19">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-13">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id20">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-14">Authors</a></h2>
<ul class="simple">
<li>Onestein</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id21">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-15">Contributors</a></h2>
<ul class="simple">
<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</a>&gt;</li>
<li>Kitti U. &lt;<a class="reference external" href="mailto:kittiu&#64;ecosoft.co.th">kittiu&#64;ecosoft.co.th</a>&gt;</li>
<li>Saran Lim. &lt;<a class="reference external" href="mailto:saranl&#64;ecosoft.co.th">saranl&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</div>
<div class="section" id="other-credits">
<h2><a class="toc-backref" href="#id22">Other credits</a></h2>
<h2><a class="toc-backref" href="#toc-entry-16">Other credits</a></h2>
<p>Part of the code in this module (in particular the computation of the spread lines)
is highly inspired by the Assets Management module from the standard
Odoo 11.0 Community developed by Odoo SA.</p>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id23">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-17">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>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/astirpe"><img alt="astirpe" src="https://github.com/astirpe.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/14.0/account_spread_cost_revenue">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/16.0/account_spread_cost_revenue">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

@ -1,61 +0,0 @@
odoo.define("account_spread_cost_revenue.widget", function (require) {
"use strict";
var AbstractField = require("web.AbstractField");
var core = require("web.core");
var registry = require("web.field_registry");
var _t = core._t;
var AccountSpreadWidget = AbstractField.extend({
events: _.extend({}, AbstractField.prototype.events, {
click: "_onClick",
}),
noLabel: true,
/**
* @override
*/
isSet: function () {
return this.value !== "unavailable";
},
/**
* @override
* @private
*/
_render: function () {
var className = "";
var style = "btn fa fa-arrow-circle-right o_spread_line ";
var title = "";
if (this.recordData.spread_check === "linked") {
className = "o_is_linked";
title = _t("Linked to spread");
} else {
title = _t("Not linked to spread");
}
var $button = $("<button/>", {
type: "button",
title: title,
}).addClass(style + className);
this.$el.html($button);
},
/**
* @private
* @param {MouseEvent} event
*/
_onClick: function (event) {
event.stopPropagation();
this.trigger_up("button_clicked", {
attrs: {
name: "spread_details",
type: "object",
},
record: this.record,
});
},
});
registry.add("spread_line_widget", AccountSpreadWidget);
});

View File

@ -1,5 +0,0 @@
.o_web_client .o_spread_line {
&.o_is_linked {
color: theme-color("success");
}
}

View File

@ -58,7 +58,6 @@ class TestAccountInvoiceAutoSpread(TestAccountInvoiceSpread):
],
}
)
template2._check_auto_spread_ids_unique()
self.assertFalse(self.vendor_bill_line.spread_id)
with self.assertRaises(UserError): # too many auto_spread_ids matched

View File

@ -33,14 +33,14 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"code": "X2120",
"name": "Expenses - (test)",
"user_type_id": self.env.ref("account.data_account_type_expenses").id,
"account_type": "expense",
}
)
a_sale = self.env["account.account"].create(
{
"code": "X2020",
"name": "Product Sales - (test)",
"user_type_id": self.env.ref("account.data_account_type_revenue").id,
"account_type": "expense_direct_cost",
}
)
@ -67,9 +67,7 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"name": "Test account payable",
"code": "321spread",
"user_type_id": self.env.ref(
"account.data_account_type_other_income"
).id,
"account_type": "income_other",
"reconcile": True,
}
)
@ -78,9 +76,7 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"name": "Test account receivable",
"code": "322spread",
"user_type_id": self.env.ref(
"account.data_account_type_other_income"
).id,
"account_type": "income_other",
"reconcile": True,
}
)
@ -89,9 +85,7 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"name": "test spread account_payable",
"code": "765spread",
"user_type_id": self.env.ref(
"account.data_account_type_other_income"
).id,
"account_type": "income_other",
"reconcile": True,
}
)
@ -100,9 +94,7 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"name": "test spread account_receivable",
"code": "766spread",
"user_type_id": self.env.ref(
"account.data_account_type_other_income"
).id,
"account_type": "income_other",
"reconcile": True,
}
)
@ -120,9 +112,17 @@ class TestAccountInvoiceSpread(common.TransactionCase):
self.vendor_bill_line.account_id.reconcile = True
self.invoice_line.account_id.reconcile = True
analytic_tags = [(6, 0, self.env.ref("analytic.tag_contract").ids)]
analytic_plan = self.env["account.analytic.plan"].create(
{"name": "Plan Test", "company_id": False}
)
self.analytic_account = self.env["account.analytic.account"].create(
{"name": "test account"}
{"name": "test account", "plan_id": analytic_plan.id}
)
self.distribution = self.env["account.analytic.distribution.model"].create(
{
"partner_id": self.vendor_bill.partner_id.id,
"analytic_distribution": {self.analytic_account.id: 100},
}
)
self.spread = (
self.env["account.spread"]
@ -139,8 +139,11 @@ class TestAccountInvoiceSpread(common.TransactionCase):
"estimated_amount": 1000.0,
"journal_id": self.vendor_bill.journal_id.id,
"invoice_type": "in_invoice",
"account_analytic_id": self.analytic_account.id,
"analytic_tag_ids": analytic_tags,
"analytic_distribution": self.distribution._get_distribution(
{
"partner_id": self.vendor_bill.partner_id.id,
}
),
}
]
)
@ -248,7 +251,6 @@ class TestAccountInvoiceSpread(common.TransactionCase):
{
"groups_id": [
(4, self.env.ref("analytic.group_analytic_accounting").id),
(4, self.env.ref("analytic.group_analytic_tags").id),
],
}
)
@ -279,9 +281,9 @@ class TestAccountInvoiceSpread(common.TransactionCase):
line.create_move()
self.assertTrue(line.move_id)
for ml in line.move_id.line_ids:
analytic_tag = self.env.ref("analytic.tag_contract")
self.assertEqual(ml.analytic_account_id, self.analytic_account)
self.assertEqual(ml.analytic_tag_ids, analytic_tag)
self.assertEqual(
ml.analytic_distribution, self.spread.analytic_distribution
)
self.spread.invoice_id.button_cancel()
@ -558,10 +560,10 @@ class TestAccountInvoiceSpread(common.TransactionCase):
if spread_ml.credit:
self.assertFalse(spread_ml.full_reconcile_id)
action_reconcile_view = self.spread2.open_reconcile_view()
self.assertTrue(isinstance(action_reconcile_view, dict))
self.assertFalse(action_reconcile_view.get("domain")[0][2])
self.assertTrue(action_reconcile_view.get("context"))
action_posted_view = self.spread2.open_posted_view()
self.assertTrue(isinstance(action_posted_view, dict))
self.assertFalse(action_posted_view.get("domain")[0][2])
self.assertTrue(action_posted_view.get("context"))
def test_11_link_vendor_bill_line_with_spread_sheet(self):
invoice_form = Form(self.vendor_bill)
@ -625,10 +627,10 @@ class TestAccountInvoiceSpread(common.TransactionCase):
self.assertEqual(spread_ml.account_id, expense_account)
self.assertFalse(spread_ml.full_reconcile_id)
action_reconcile_view = self.spread.open_reconcile_view()
self.assertTrue(isinstance(action_reconcile_view, dict))
self.assertTrue(action_reconcile_view.get("domain")[0][2])
self.assertTrue(action_reconcile_view.get("context"))
action_posted_view = self.spread.open_posted_view()
self.assertTrue(isinstance(action_posted_view, dict))
self.assertTrue(action_posted_view.get("domain")[0][2])
self.assertTrue(action_posted_view.get("context"))
action_spread_details = self.vendor_bill_line.spread_details()
self.assertTrue(isinstance(action_spread_details, dict))
@ -679,11 +681,11 @@ class TestAccountInvoiceSpread(common.TransactionCase):
for invoice_ml in invoice_mls:
self.assertEqual(invoice_ml.account_id, balance_sheet)
action_reconcile_view = self.spread2.open_reconcile_view()
self.assertTrue(isinstance(action_reconcile_view, dict))
self.assertFalse(action_reconcile_view.get("domain")[0][2])
self.assertFalse(action_reconcile_view.get("res_id"))
self.assertTrue(action_reconcile_view.get("context"))
action_posted_view = self.spread2.open_posted_view()
self.assertTrue(isinstance(action_posted_view, dict))
self.assertTrue(action_posted_view.get("domain")[0][2])
self.assertFalse(action_posted_view.get("res_id"))
self.assertTrue(action_posted_view.get("context"))
action_spread_details = self.invoice_line.spread_details()
self.assertTrue(isinstance(action_spread_details, dict))

View File

@ -3,7 +3,7 @@
import datetime
from psycopg2 import IntegrityError
from psycopg2.errors import NotNullViolation
from odoo.exceptions import ValidationError
from odoo.tests import Form, common
@ -22,16 +22,11 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
{"name": "Vendor Bills - Test", "code": "TEST2", "type": "purchase"}
)
type_receivable = self.env.ref("account.data_account_type_receivable")
type_expenses = self.env.ref("account.data_account_type_expenses")
type_payable = self.env.ref("account.data_account_type_payable")
type_revenue = self.env.ref("account.data_account_type_revenue")
self.credit_account = self.env["account.account"].create(
{
"name": "test_account_receivable",
"code": "123",
"user_type_id": type_receivable.id,
"account_type": "asset_receivable",
"reconcile": True,
}
)
@ -40,7 +35,7 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
{
"name": "test account_expenses",
"code": "765",
"user_type_id": type_expenses.id,
"account_type": "expense",
"reconcile": True,
}
)
@ -49,7 +44,7 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
{
"name": "test_account_payable",
"code": "321",
"user_type_id": type_payable.id,
"account_type": "liability_payable",
"reconcile": True,
}
)
@ -58,7 +53,7 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
{
"name": "test_account_revenue",
"code": "864",
"user_type_id": type_revenue.id,
"account_type": "asset_receivable",
"reconcile": True,
}
)
@ -85,8 +80,7 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
self.assertFalse(spread.invoice_line_ids)
self.assertFalse(spread.invoice_line_id)
self.assertFalse(spread.invoice_id)
self.assertFalse(spread.account_analytic_id)
self.assertFalse(spread.analytic_tag_ids)
self.assertFalse(spread.analytic_distribution)
self.assertTrue(spread.move_line_auto_post)
self.assertEqual(spread.name, "test")
self.assertEqual(spread.invoice_type, "out_invoice")
@ -116,14 +110,29 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
@mute_logger("odoo.sql_db")
def test_03_no_defaults(self):
with self.assertRaises(IntegrityError):
with self.assertRaises(NotNullViolation):
self.env["account.spread"].create({"name": "test"})
with self.assertRaises(NotNullViolation):
self.env["account.spread"].create(
{"name": "test", "invoice_type": "out_invoice"}
)
@mute_logger("odoo.sql_db")
def test_04_no_defaults(self):
with self.assertRaises(IntegrityError):
with self.assertRaises(NotNullViolation):
self.env["account.spread"].create(
{"name": "test", "invoice_type": "out_invoice"}
{
"name": "test",
"debit_account_id": self.debit_account.id,
"credit_account_id": self.credit_account.id,
}
)
with self.assertRaises(NotNullViolation):
self.env["account.spread"].create(
{
"name": "test",
"credit_account_id": self.credit_account.id,
}
)
def test_05_config_settings(self):
@ -137,6 +146,8 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
self.assertTrue(self.env.company.default_spread_revenue_journal_id)
self.assertTrue(self.env.company.default_spread_expense_journal_id)
self.env.user.groups_id += self.env.ref("base.group_multi_company")
spread_form = Form(self.env["account.spread"])
spread_form.name = "test"
spread_form.invoice_type = "in_invoice"
@ -149,8 +160,7 @@ class TestAccountSpreadCostRevenue(common.TransactionCase):
self.assertFalse(spread.invoice_line_ids)
self.assertFalse(spread.invoice_line_id)
self.assertFalse(spread.invoice_id)
self.assertFalse(spread.account_analytic_id)
self.assertFalse(spread.analytic_tag_ids)
self.assertFalse(spread.analytic_distribution)
self.assertTrue(spread.move_line_auto_post)
defaults = self.env["account.spread"].default_get(["company_id", "currency_id"])

View File

@ -4,14 +4,12 @@
import datetime
from odoo.exceptions import UserError
from odoo.tests import common
from odoo.tests import Form, common
class TestComputeSpreadBoard(common.TransactionCase):
def setUp(self):
super().setUp()
type_receivable = self.env.ref("account.data_account_type_receivable")
type_expenses = self.env.ref("account.data_account_type_expenses")
journal = self.env["account.journal"].create(
{"name": "Test", "type": "general", "code": "test"}
@ -21,7 +19,7 @@ class TestComputeSpreadBoard(common.TransactionCase):
{
"name": "test_account_receivable",
"code": "123",
"user_type_id": type_receivable.id,
"account_type": "asset_receivable",
"reconcile": True,
}
)
@ -30,7 +28,7 @@ class TestComputeSpreadBoard(common.TransactionCase):
{
"name": "test account_expenses",
"code": "765",
"user_type_id": type_expenses.id,
"account_type": "expense",
"reconcile": True,
}
)
@ -39,7 +37,7 @@ class TestComputeSpreadBoard(common.TransactionCase):
{
"name": "test spread account_expenses",
"code": "321",
"user_type_id": type_expenses.id,
"account_type": "expense",
"reconcile": True,
}
)
@ -72,6 +70,34 @@ class TestComputeSpreadBoard(common.TransactionCase):
}
)
self.spread3 = self.env["account.spread"].create(
{
"name": "test by cal days",
"debit_account_id": self.spread_account.id,
"credit_account_id": self.expense_account.id,
"period_number": 12,
"period_type": "month",
"spread_date": "2017-02-01",
"estimated_amount": 12000.0,
"journal_id": journal.id,
"invoice_type": "out_invoice",
"days_calc": True,
}
)
self.template = self.env["account.spread.template"].create(
{
"name": "test",
"spread_type": "purchase",
"period_number": 5,
"period_type": "month",
"start_date": "2017-01-01",
"spread_account_id": self.spread_account.id,
"spread_journal_id": journal.id,
"days_calc": True,
}
)
def test_01_supplier_invoice(self):
self.spread.compute_spread_board()
spread_lines = self.spread.line_ids
@ -617,3 +643,83 @@ class TestComputeSpreadBoard(common.TransactionCase):
self.assertAlmostEqual(self.spread.unspread_amount, 682.81)
self.assertAlmostEqual(self.spread.unposted_amount, 682.81)
def test_19_supplier_invoice_calc_day(self):
self.assertTrue(self.spread3.days_calc)
self.spread3.compute_spread_board()
spread_lines = self.spread3.line_ids
self.assertEqual(len(spread_lines), 12)
# Calculate by day has formula:
# (amount spread cost / all spread cost day) * day of <period_type>
self.assertAlmostEqual(920.55, spread_lines[0].amount)
self.assertAlmostEqual(1019.18, spread_lines[1].amount)
self.assertAlmostEqual(986.30, spread_lines[2].amount)
self.assertAlmostEqual(1019.18, spread_lines[3].amount)
self.assertAlmostEqual(986.30, spread_lines[4].amount)
self.assertAlmostEqual(1019.18, spread_lines[5].amount)
self.assertAlmostEqual(1019.18, spread_lines[6].amount)
self.assertAlmostEqual(986.30, spread_lines[7].amount)
self.assertAlmostEqual(1019.18, spread_lines[8].amount)
self.assertAlmostEqual(986.30, spread_lines[9].amount)
self.assertAlmostEqual(1019.18, spread_lines[10].amount)
self.assertAlmostEqual(1019.17, spread_lines[11].amount) # total left
self.assertEqual(datetime.date(2017, 2, 28), spread_lines[0].date)
self.assertEqual(datetime.date(2017, 3, 31), spread_lines[1].date)
self.assertEqual(datetime.date(2017, 4, 30), spread_lines[2].date)
self.assertEqual(datetime.date(2017, 5, 31), spread_lines[3].date)
self.assertEqual(datetime.date(2017, 6, 30), spread_lines[4].date)
self.assertEqual(datetime.date(2017, 7, 31), spread_lines[5].date)
self.assertEqual(datetime.date(2017, 8, 31), spread_lines[6].date)
self.assertEqual(datetime.date(2017, 9, 30), spread_lines[7].date)
self.assertEqual(datetime.date(2017, 10, 31), spread_lines[8].date)
self.assertEqual(datetime.date(2017, 11, 30), spread_lines[9].date)
self.assertEqual(datetime.date(2017, 12, 31), spread_lines[10].date)
self.assertEqual(datetime.date(2018, 1, 31), spread_lines[11].date)
# Period Type is 'Quarter'
self.spread3.period_type = "quarter"
self.spread3.compute_spread_board()
spread_lines = self.spread3.line_ids
self.assertEqual(len(spread_lines), 12)
self.assertAlmostEqual(325.27, spread_lines[0].amount)
self.assertAlmostEqual(1068.73, spread_lines[1].amount)
self.assertAlmostEqual(1068.73, spread_lines[2].amount)
self.assertAlmostEqual(1057.12, spread_lines[3].amount)
self.assertAlmostEqual(1045.50, spread_lines[4].amount)
self.assertAlmostEqual(1068.73, spread_lines[5].amount)
self.assertAlmostEqual(1068.73, spread_lines[6].amount)
self.assertAlmostEqual(1057.12, spread_lines[7].amount)
self.assertAlmostEqual(1045.50, spread_lines[8].amount)
self.assertAlmostEqual(1068.73, spread_lines[9].amount)
self.assertAlmostEqual(1068.73, spread_lines[10].amount)
self.assertAlmostEqual(1057.11, spread_lines[11].amount) # total left
# Period Type is 'Year' and spread date is not first month
self.spread3.period_type = "year"
self.spread3.spread_date = "2017-02-02"
self.spread3.compute_spread_board()
spread_lines = self.spread3.line_ids
self.assertEqual(len(spread_lines), 13)
self.assertAlmostEqual(73.92, spread_lines[0].amount)
self.assertAlmostEqual(999.32, spread_lines[1].amount)
self.assertAlmostEqual(999.32, spread_lines[2].amount)
self.assertAlmostEqual(1002.05, spread_lines[3].amount)
self.assertAlmostEqual(999.32, spread_lines[4].amount)
self.assertAlmostEqual(999.32, spread_lines[5].amount)
self.assertAlmostEqual(999.32, spread_lines[6].amount)
self.assertAlmostEqual(1002.05, spread_lines[7].amount)
self.assertAlmostEqual(999.32, spread_lines[8].amount)
self.assertAlmostEqual(999.32, spread_lines[9].amount)
self.assertAlmostEqual(999.32, spread_lines[10].amount)
self.assertAlmostEqual(1002.05, spread_lines[11].amount)
self.assertAlmostEqual(925.37, spread_lines[12].amount)
def test_20_supplier_invoice_template(self):
"""Test onchange template"""
self.assertEqual(self.spread3.invoice_type, "out_invoice")
with Form(self.spread3) as sp:
sp.template_id = self.template
sp.credit_account_id = self.expense_account
sp.save()
self.assertEqual(self.spread3.invoice_type, "in_invoice")

View File

@ -10,9 +10,46 @@
>
<field
name="spread_check"
widget="spread_line_widget"
invisible="1"
groups="account.group_account_user,account.group_account_manager"
/>
<button
name="spread_details"
type="object"
class="btn btn-link"
icon="fa-arrow-circle-right"
title="Not linked to any spread board"
attrs="{'invisible': [('spread_check', '!=', 'unlinked')]}"
groups="account.group_account_user,account.group_account_manager"
/>
<button
name="spread_details"
type="object"
class="btn btn-success"
icon="fa-arrow-circle-right"
title="Linked to spread board"
attrs="{'invisible': [('spread_check', '!=', 'linked')]}"
groups="account.group_account_user,account.group_account_manager"
/>
</xpath>
<xpath
expr="//field[@name='line_ids']/tree//button[@name='action_automatic_entry']"
position="after"
>
<field
name="spread_check"
invisible="1"
groups="account.group_account_user,account.group_account_manager"
/>
<button
name="spread_details"
type="object"
class="btn btn-success"
icon="fa-arrow-circle-right"
title="Linked to spread board"
groups="account.group_account_user,account.group_account_manager"
attrs="{'invisible': [('spread_check', '!=', 'linked')], 'column_invisible': ['|', ('parent.move_type', '=', 'entry'), ('parent.state', '!=', 'posted')]}"
/>
</xpath>
</field>
</record>
@ -25,7 +62,7 @@
<field
name="domain"
>[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="account.view_move_line_tree_grouped" />
<field name="view_id" ref="account.view_move_line_tree" />
<field name="view_mode">tree,pivot,graph,form,kanban</field>
</record>
</odoo>

View File

@ -37,11 +37,11 @@
<sheet>
<div name="button_box" class="oe_button_box">
<button
name="open_reconcile_view"
name="open_posted_view"
class="oe_stat_button"
icon="fa-bars"
type="object"
string="Reconciled entries"
string="Posted entries"
>
</button>
</div>
@ -91,7 +91,7 @@
/>
<div
attrs="{'invisible': [('use_invoice_line_account', '=', True)]}"
colspan="2"
colspan="3"
>
<span
class="help-block"
@ -112,7 +112,7 @@
</div>
<div
attrs="{'invisible': [('use_invoice_line_account', '!=', True)]}"
colspan="2"
colspan="3"
>
<span
class="help-block"
@ -134,7 +134,7 @@
<field
name="debit_account_id"
required="1"
domain="[('company_id', '=', company_id), ('deprecated', '=', False), ('internal_type','!=','liquidity'), ('internal_group', '!=', 'off_balance')]"
domain="[('deprecated', '=', False), ('account_type', 'not in', ('asset_cash','liability_credit_card')), ('internal_group', '!=', 'off_balance')]"
attrs="{'readonly':[('invoice_line_id','!=',False)]}"
/>
<span
@ -161,7 +161,7 @@
/>
<div
attrs="{'invisible': [('use_invoice_line_account', '=', True)]}"
colspan="2"
colspan="3"
>
<span
class="help-block"
@ -182,7 +182,7 @@
</div>
<div
attrs="{'invisible': [('use_invoice_line_account', '!=', True)]}"
colspan="2"
colspan="3"
>
<span
class="help-block"
@ -204,7 +204,7 @@
<field
name="credit_account_id"
required="1"
domain="[('company_id', '=', company_id), ('deprecated', '=', False), ('internal_type','!=','liquidity'), ('internal_group', '!=', 'off_balance')]"
domain="[('deprecated', '=', False), ('account_type', 'not in', ('asset_cash','liability_credit_card')), ('internal_group', '!=', 'off_balance')]"
attrs="{'readonly':[('invoice_line_id','!=',False)]}"
/>
<span
@ -244,12 +244,9 @@
<field name="period_number" />
<field name="period_type" />
<field name="spread_date" />
<field
name="journal_id"
domain="[('company_id', '=', company_id)]"
widget="selection"
/>
<field name="days_calc" />
<field name="suitable_journal_ids" invisible="1" />
<field name="journal_id" widget="selection" />
</group>
</group>
<notebook name="notebook">
@ -303,6 +300,7 @@
string="Create All Moves"
type="object"
icon="fa-play"
colspan="2"
attrs="{'invisible':[('display_create_all_moves','!=',True)]}"
/>
<field
@ -335,15 +333,9 @@
</group>
<group>
<field
name="account_analytic_id"
domain="[('company_id', '=', company_id)]"
name="analytic_distribution"
groups="analytic.group_analytic_accounting"
options="{'no_create': True}"
/>
<field
name="analytic_tag_ids"
groups="analytic.group_analytic_accounting"
widget="many2many_tags"
widget="analytic_distribution"
/>
</group>
</group>
@ -357,22 +349,6 @@
</form>
</field>
</record>
<record id="view_account_spread_account_manager" model="ir.ui.view">
<field name="model">account.spread</field>
<field name="inherit_id" ref="view_account_spread" />
<field name="groups_id" eval="[(4, ref('account.group_account_manager'))]" />
<field name="arch" type="xml">
<tree position="attributes">
<attribute name="editable">1</attribute>
</tree>
<field name="amount" position="attributes">
<attribute name="readonly" />
</field>
<field name="line_ids" position="attributes">
<attribute name="readonly" />
</field>
</field>
</record>
<record id="view_account_spread_tree" model="ir.ui.view">
<field name="model">account.spread</field>
<field name="arch" type="xml">

View File

@ -32,20 +32,21 @@
<field name="use_invoice_line_account" />
<field
name="spread_account_id"
domain="[('company_id', '=', company_id), ('deprecated', '=', False), ('internal_type','!=','liquidity'), ('internal_group', '!=', 'off_balance')]"
domain="[('deprecated', '=', False), ('account_type', 'not in', ('asset_cash','liability_credit_card')), ('internal_group', '!=', 'off_balance')]"
options="{'no_create': True}"
attrs="{'required': [('use_invoice_line_account', '!=', True)], 'invisible': [('use_invoice_line_account', '=', True)]}"
/>
<field
name="exp_rev_account_id"
attrs="{'invisible': [('use_invoice_line_account', '=', False)], 'required': [('use_invoice_line_account', '=', True)]}"
domain="[('company_id', '=', company_id), ('deprecated', '=', False)]"
domain="[('deprecated', '=', False)]"
options="{'no_create': True}"
/>
<field name="spread_journal_id" widget="selection" />
<field
name="spread_journal_id"
domain="[('company_id', '=', company_id)]"
widget="selection"
name="analytic_distribution"
groups="analytic.group_analytic_accounting"
widget="analytic_distribution"
/>
</group>
</group>
@ -65,10 +66,6 @@
<field name="name" />
<field name="product_id" />
<field name="account_id" />
<field
name="analytic_account_id"
groups="analytic.group_analytic_accounting"
/>
</tree>
</field>
</sheet>

View File

@ -163,8 +163,7 @@ class AccountSpreadInvoiceLineLinkWizard(models.TransientModel):
self.exp_rev_account_id or self.invoice_line_id.account_id
)
analytic_account = self.invoice_line_id.analytic_account_id
analytic_tags = self.invoice_line_id.analytic_tag_ids
analytic_distribution = self.invoice_line_id.analytic_distribution
date_invoice = self.invoice_id.invoice_date or fields.Date.today()
return {
@ -183,8 +182,7 @@ class AccountSpreadInvoiceLineLinkWizard(models.TransientModel):
"default_debit_account_id": debit_account.id,
"default_credit_account_id": credit_account.id,
"default_journal_id": self.spread_journal_id.id,
"default_account_analytic_id": analytic_account.id,
"default_analytic_tag_ids": analytic_tags.ids,
"default_analytic_distribution": analytic_distribution,
"default_spread_date": date_invoice,
},
}
@ -214,16 +212,13 @@ class AccountSpreadInvoiceLineLinkWizard(models.TransientModel):
else:
spread_vals["debit_account_id"] = account.id
analytic_account = self.invoice_line_id.analytic_account_id
spread_vals["account_analytic_id"] = analytic_account.id
analytic_distribution = self.invoice_line_id.analytic_distribution
spread_vals["analytic_distribution"] = analytic_distribution
spread_vals["currency_id"] = self.invoice_id.currency_id.id
spread = self.env["account.spread"].create(spread_vals)
analytic_tags = self.invoice_line_id.analytic_tag_ids
spread.analytic_tag_ids = analytic_tags
self.invoice_line_id.spread_id = spread
return {
"name": _("Spread Details"),

View File

@ -37,19 +37,18 @@
<field
name="spread_account_id"
attrs="{'invisible': [('spread_action_type', '!=', 'new')],'required': [('spread_action_type', '=', 'new')]}"
domain="[('company_id', '=', company_id), ('deprecated', '=', False), ('internal_type','!=','liquidity'), ('internal_group', '!=', 'off_balance')]"
domain="[('deprecated', '=', False), ('account_type', 'not in', ('asset_cash','liability_credit_card')), ('internal_group', '!=', 'off_balance')]"
options="{'no_create': True}"
/>
<field
name="exp_rev_account_id"
attrs="{'invisible': ['|', ('use_invoice_line_account', '=', False), ('spread_action_type', '!=', 'new')], 'required': [('use_invoice_line_account', '=', True)]}"
domain="[('company_id', '=', company_id), ('deprecated', '=', False)]"
domain="[('deprecated', '=', False)]"
options="{'no_create': True}"
/>
<field
name="spread_journal_id"
attrs="{'invisible': [('spread_action_type', '!=', 'new')],'required': [('spread_action_type', '=', 'new')]}"
domain="[('company_id', '=', company_id)]"
options="{'no_create': True}"
/>
</group>

View File

@ -0,0 +1 @@
../../../../account_spread_cost_revenue

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)