diff --git a/addons/account/models/__init__.py b/addons/account/models/__init__.py
index d9e2695b020..0322c41fd1d 100644
--- a/addons/account/models/__init__.py
+++ b/addons/account/models/__init__.py
@@ -7,6 +7,7 @@ from . import account_account_tag
from . import account_account
from . import account_journal
from . import account_tax
+from . import account_tax_carryover_line
from . import account_tax_report
from . import account_reconcile_model
from . import account_payment_term
diff --git a/addons/account/models/account_tax_carryover_line.py b/addons/account/models/account_tax_carryover_line.py
new file mode 100644
index 00000000000..ee9a7065288
--- /dev/null
+++ b/addons/account/models/account_tax_carryover_line.py
@@ -0,0 +1,27 @@
+from odoo import api, fields, models, _
+
+from odoo.exceptions import ValidationError
+
+class AccountTaxCarryoverLine(models.Model):
+ _name = 'account.tax.carryover.line'
+ _description = 'Tax carryover line'
+
+ name = fields.Char(required=True)
+ amount = fields.Float(required=True, default=0.0)
+ date = fields.Date(required=True, default=fields.Date.context_today, readonly=True)
+ tax_report_line_id = fields.Many2one(comodel_name='account.tax.report.line', string="Tax report line")
+ tax_report_country_id = fields.Many2one(related='tax_report_line_id.report_id.country_id')
+ company_id = fields.Many2one(comodel_name='res.company', string='Company',
+ required=True,
+ default=lambda self: self.env.company)
+ foreign_vat_fiscal_position_id = fields.Many2one(comodel_name='account.fiscal.position',
+ string='Fiscal position',
+ help="The foreign fiscal position for which this carryover is made.",
+ domain=[('company_id', '=', company_id),
+ ('country_id', '=', tax_report_country_id),
+ ('foreign_vat', '!=', False)])
+
+ @api.constrains('foreign_vat_fiscal_position_id')
+ def _check_fiscal_position(self):
+ if self.foreign_vat_fiscal_position_id and not self.foreign_vat_fiscal_position_id.country_id == self.tax_report_country_id:
+ raise ValidationError(_("The country of the fiscal position must be this report line's report country."))
diff --git a/addons/account/models/account_tax_report.py b/addons/account/models/account_tax_report.py
index 2533002972a..e7b34becc05 100644
--- a/addons/account/models/account_tax_report.py
+++ b/addons/account/models/account_tax_report.py
@@ -75,11 +75,12 @@ class AccountTaxReport(models.Model):
lines_to_treat = list(to_yield.children_line_ids.sorted(lambda x: x.sequence)) + lines_to_treat[1:]
yield to_yield
- def get_checks_to_perform(self, d):
+ def get_checks_to_perform(self, amounts, carried_over):
""" To override in localizations
If value is a float, it will be formatted with format_value
The line is not displayed if it is falsy (0, 0.0, False, ...)
- :param d: the mapping dictionay between codes and values
+ :param amounts: the mapping dictionary between codes and values
+ :param carried_over: the mapping dictionary between codes and whether they are carried over
:return: iterable of tuple (name, value)
"""
self.ensure_one()
@@ -107,13 +108,34 @@ class AccountTaxReportLine(models.Model):
parent_path = fields.Char(index=True)
report_id = fields.Many2one(string="Tax Report", required=True, comodel_name='account.tax.report', ondelete='cascade', help="The parent tax report of this line")
- #helper to create tags (positive and negative) on report line creation
+ # helper to create tags (positive and negative) on report line creation
tag_name = fields.Char(string="Tag Name", help="Short name for the tax grid corresponding to this report line. Leave empty if this report line should not correspond to any such grid.")
- #fields used in specific localization reports, where a report line isn't simply the given by the sum of account.move.line with selected tags
+ # fields used in specific localization reports, where a report line isn't simply the given by the sum of account.move.line with selected tags
code = fields.Char(string="Code", help="Optional unique code to refer to this line in total formulas")
formula = fields.Char(string="Formula", help="Python expression used to compute the value of a total line. This field is mutually exclusive with tag_name, setting it turns the line to a total line. Tax report line codes can be used as variables in this expression to refer to the balance of the corresponding lines in the report. A formula cannot refer to another line using a formula.")
+ # fields used to carry over amounts between periods
+
+ # The selection should be filled in localizations using the system
+ carry_over_condition_method = fields.Selection(
+ selection=[('no_negative_amount_carry_over_condition', 'No negative amount')],
+ string="Carry over method",
+ help="The method used to determine if this line should be carried over."
+ )
+ carry_over_destination_line_id = fields.Many2one(
+ string="Carry over to",
+ comodel_name="account.tax.report.line",
+ domain=[('tag_name', '!=', False)],
+ help="The line to which the value of this line will be carried over to if needed."
+ " If left empty the line will carry over to itself."
+ )
+ carryover_line_ids = fields.One2many(
+ string="Carryover lines",
+ comodel_name='account.tax.carryover.line',
+ inverse_name='tax_report_line_id',
+ )
+
@api.model
def create(self, vals):
# Manage tags
@@ -264,3 +286,32 @@ class AccountTaxReportLine(models.Model):
if neg_tags.name != '-'+record.tag_name or pos_tags.name != '+'+record.tag_name:
raise ValidationError(_("The tags linked to a tax report line should always match its tag name."))
+
+ def _get_carryover_bounds(self, options, line_amount, carried_over_amount):
+ """
+ Check if the line will be carried over, by checking the condition method set on the line.
+ Do not override this method, but instead set your condition methods on each lines.
+ :param options: The options of the reports
+ :param line_amount: The amount on the line
+ :param carried_over_amount: The amount carried over for this line
+ :return: A tuple containing the lower and upper bounds from which the line will be carried over.
+ E.g. (0, 42) : Lines which value is below 0 or above 42 will be carried over.
+ E.g. (0, None) : Only lines which value is below 0 will be carried over.
+ E.g. None : This line will never be carried over.
+ """
+ self.ensure_one()
+ # Carry over is disabled by default, but if there is a carry over condition method on the line we are
+ # calling it first. That way we can have a default carryover condition for the whole report (carryover_bounds)
+ # and specialized condition for specific lines if needed
+ if self.carry_over_condition_method:
+ condition_method = getattr(self, self.carry_over_condition_method, False)
+ if condition_method:
+ return condition_method(options, line_amount, carried_over_amount)
+
+ return None
+
+ def no_negative_amount_carry_over_condition(self, options, line_amount, carried_over_amount):
+ # The bounds are (0, None).
+ # Lines below 0 will be set to 0 and reduce the balance of the carryover.
+ # Lines above 0 will never be carried over
+ return (0, None)
diff --git a/addons/account/security/account_security.xml b/addons/account/security/account_security.xml
index 6fc42d68ea8..5fe852d5d07 100644
--- a/addons/account/security/account_security.xml
+++ b/addons/account/security/account_security.xml
@@ -275,5 +275,10 @@
['|',('company_id','=',False),('company_id', 'in', company_ids)]
+
+ Carry over line multi-company
+
+ [('company_id', 'in', company_ids)]
+
diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv
index cddbb5372f2..b6a47288b84 100644
--- a/addons/account/security/ir.model.access.csv
+++ b/addons/account/security/ir.model.access.csv
@@ -91,6 +91,8 @@ access_account_tax_repartition_line_invoice,account.tax repartition.line.invoice
access_account_tax_repartition_line_manager,account.tax repartition.line.manager,model_account_tax_repartition_line,account.group_account_manager,1,1,1,1
access_account_tax_report_line_readonly,account.tax.report.line.invoice,model_account_tax_report_line,account.group_account_readonly,1,0,0,0
access_account_tax_report_line_ac_user,account.tax.report.line.ac.user,model_account_tax_report_line,account.group_account_manager,1,1,1,1
+access_account_tax_carryover_line_readonly,account.tax.carryover.line.invoice,model_account_tax_carryover_line,account.group_account_readonly,1,0,0,0
+access_account_tax_carryover_line_ac_user,account.tax.carryover.line.ac.user,model_account_tax_carryover_line,account.group_account_manager,1,1,1,1
access_account_tax_report_invoice,account.tax.report.invoice,model_account_tax_report,account.group_account_readonly,1,0,0,0
access_account_tax_report_ac_user,account.tax.report.ac.user,model_account_tax_report,account.group_account_manager,1,1,1,1
access_account_tax_group_internal_user,account.tax.group internal user,model_account_tax_group,base.group_user,1,0,0,0
@@ -143,4 +145,4 @@ access_account_analytic_default,account.analytic.default,model_account_analytic_
access_account_analytic_default_analytic,account.analytic.default analytic,model_account_analytic_default,analytic.group_analytic_accounting,1,0,0,0
access_account_analytic_default_invoice,account.analytic.default invoice,model_account_analytic_default,account.group_account_invoice,1,1,1,1
access_account_tour_upload_bill,account.tour.upload.bill,model_account_tour_upload_bill,account.group_account_manager,1,1,1,0
-access_account_tour_upload_bill_email_confirm,account.tour.upload.bill.email.confirm,model_account_tour_upload_bill_email_confirm,account.group_account_manager,1,1,1,0
\ No newline at end of file
+access_account_tour_upload_bill_email_confirm,account.tour.upload.bill.email.confirm,model_account_tour_upload_bill_email_confirm,account.group_account_manager,1,1,1,0
diff --git a/addons/account/views/account_tax_report_views.xml b/addons/account/views/account_tax_report_views.xml
index 26737629c9a..9e31fb76e81 100644
--- a/addons/account/views/account_tax_report_views.xml
+++ b/addons/account/views/account_tax_report_views.xml
@@ -49,6 +49,21 @@
+
+ account.tax.carryover.line.tree
+ account.tax.carryover.line
+
+
+
+
+
+
+
+
+
+
+
+
account.tax.report.line.form
account.tax.report.line
@@ -70,9 +85,22 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_be/data/account_tax_report_data.xml b/addons/l10n_be/data/account_tax_report_data.xml
index 6b21b5c1124..d2664138fbb 100644
--- a/addons/l10n_be/data/account_tax_report_data.xml
+++ b/addons/l10n_be/data/account_tax_report_data.xml
@@ -160,6 +160,7 @@
1
+ no_negative_amount_carry_over_condition
@@ -169,6 +170,7 @@
2
+ no_negative_amount_carry_over_condition
@@ -178,6 +180,7 @@
3
+ no_negative_amount_carry_over_condition
@@ -205,6 +208,7 @@
6
+ no_negative_amount_carry_over_condition
@@ -214,6 +218,7 @@
7
+ no_negative_amount_carry_over_condition
@@ -223,6 +228,7 @@
8
+ no_negative_amount_carry_over_condition