Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] l10n_it_reverse_charge: force amount_currency set in line values #4238

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 deletions l10n_it_reverse_charge/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Copyright 2017 Lorenzo Battistini - Agile Business Group
# Copyright 2017 Marco Calcagni - Dinamiche Aziendali srl
# Copyright 2023 Simone Rubino - TAKOBI
# Copyright 2024 Nextev Srl

from odoo import api, fields, models
from odoo.exceptions import UserError
Expand Down Expand Up @@ -180,16 +181,17 @@ def compute_rc_amount_tax_main_currency(self):
The result is converted and rounded based on Company Currency
because this value is used for credit/debit.
"""
rc_tax_amount = self.get_tax_amount_added_for_rc()
rc_tax_amount_ic = self.get_tax_amount_added_for_rc()
rc_tax_amount_cc = rc_tax_amount_ic

invoice_currency = self.currency_id
company_currency = self.company_currency_id
if invoice_currency != company_currency:
rc_tax_amount = invoice_currency._convert(
rc_tax_amount, company_currency, self.company_id, self.invoice_date
rc_tax_amount_cc = invoice_currency._convert(
rc_tax_amount_ic, company_currency, self.company_id, self.invoice_date
)

return rc_tax_amount
return rc_tax_amount_ic, rc_tax_amount_cc

def rc_payment_vals(self, rc_type):
"""Values for the RC Payment Move."""
Expand All @@ -199,15 +201,20 @@ def rc_payment_vals(self, rc_type):
"date": self.date,
}

def _rc_line_values(self, account, credit, debit):
def _rc_line_values(self, account, credit, debit, amount_currency):
"""Base Values for the RC Payment Move lines."""
return {
values = {
"name": self.name,
"credit": credit,
"debit": debit,
"account_id": account.id,
"currency_id": self.currency_id.id,
}
if amount_currency:
sign = 1 if debit else -1
amount_currency = abs(amount_currency) * sign
values["amount_currency"] = amount_currency
return values

def _rc_credit_line_amounts(self, amount):
if self.is_inbound():
Expand All @@ -230,7 +237,9 @@ def rc_payment_credit_line_vals(self, line_to_reconcile):
)
account = line_to_reconcile.account_id

line_values = self._rc_line_values(account, credit, debit)
line_values = self._rc_line_values(
account, credit, debit, line_to_reconcile.amount_currency
)
line_values.update(
{
"partner_id": self.partner_id.id,
Expand All @@ -244,16 +253,18 @@ def rc_payment_debit_line_vals(self, line_to_reconcile, account):
abs(line_to_reconcile.balance),
)

line_values = self._rc_line_values(account, credit, debit)
line_values = self._rc_line_values(
account, credit, debit, line_to_reconcile.amount_currency
)
return line_values

def rc_credit_line_vals(self, account, amount):
credit, debit = self._rc_credit_line_amounts(amount)
return self._rc_line_values(account, credit, debit)
def rc_credit_line_vals(self, account, amount_ic, amount_cc):
credit, debit = self._rc_credit_line_amounts(amount_cc)
return self._rc_line_values(account, credit, debit, amount_ic)

def rc_debit_line_vals(self, account, amount):
credit, debit = self._rc_debit_line_amounts(amount)
line_values = self._rc_line_values(account, credit, debit)
def rc_debit_line_vals(self, account, amount_ic, amount_cc):
credit, debit = self._rc_debit_line_amounts(amount_cc)
line_values = self._rc_line_values(account, credit, debit, amount_ic)
line_values.update(
{
"partner_id": self.partner_id.id,
Expand All @@ -277,6 +288,7 @@ def _prepare_rc_supplier_invoice_payment(self, rc_invoice, rc_type):
line_to_reconcile = self._rc_get_move_line_to_reconcile()
payment_debit_line_data = self.rc_debit_line_vals(
line_to_reconcile.account_id,
payment_credit_line_data["amount_currency"],
payment_credit_line_data["credit"],
)
rc_payment_data["line_ids"] = [
Expand Down Expand Up @@ -318,15 +330,17 @@ def _prepare_rc_invoice_payment(self, rc_invoice, rc_type):
)

# Lines to be reconciled with the original supplier Invoice (self)
rc_tax_amount = self.compute_rc_amount_tax_main_currency()
rc_tax_amount_ic, rc_tax_amount_cc = self.compute_rc_amount_tax_main_currency()
payment_credit_line_data = self.rc_credit_line_vals(
rc_type.transitory_account_id,
rc_tax_amount,
rc_tax_amount_ic,
rc_tax_amount_cc,
)
line_to_reconcile = self._rc_get_move_line_to_reconcile()
payment_debit_line_data = self.rc_debit_line_vals(
line_to_reconcile.account_id,
rc_tax_amount,
rc_tax_amount_ic,
rc_tax_amount_cc,
)

rc_payment_data["line_ids"] = [
Expand Down
57 changes: 55 additions & 2 deletions l10n_it_reverse_charge/tests/rc_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,21 @@ def setUpClass(cls, chart_template_ref=None):
cls._create_rc_types()
cls._create_rc_type_taxes()
cls._create_fiscal_position()
cls._create_currency_rate(cls.env.ref("base.EUR").id, 1.1)

cls.supplier_extraEU = cls.partner_model.create(
{
"name": "Extra EU supplier",
"property_account_position_id": cls.fiscal_position_extra.id,
}
)
cls.supplier_extraEU_EUR = cls.partner_model.create(
{
"name": "Extra EU Euro supplier",
"property_account_position_id": cls.fiscal_position_extra_no_si.id,
"currency_id": cls.env.ref("base.EUR"),
}
)
cls.supplier_intraEU = cls.partner_model.create(
{
"name": "Intra EU supplier",
Expand Down Expand Up @@ -102,9 +110,14 @@ def setUpClass(cls, chart_template_ref=None):
)

@classmethod
def create_invoice(cls, partner, amounts, taxes=None, post=True):
def create_invoice(cls, partner, amounts, taxes=None, post=True, currency=None):
invoice = cls.init_invoice(
"in_invoice", partner=partner, post=post, amounts=amounts, taxes=taxes
"in_invoice",
partner=partner,
post=post,
amounts=amounts,
taxes=taxes,
currency=currency,
)
for line in invoice.invoice_line_ids:
line.account_id = cls.invoice_line_account.id
Expand Down Expand Up @@ -224,6 +237,20 @@ def _create_rc_types(cls):
}
)

cls.rc_type_eeu_no_selfinvoice_extra = rc_type_model.create(
{
"name": "Extra EU (selfinvoice)",
"method": "selfinvoice",
"partner_type": "other",
"with_supplier_self_invoice": False,
"partner_id": cls.env.ref("base.main_partner").id,
"journal_id": cls.journal_selfinvoice_extra.id,
"supplier_journal_id": cls.journal_cee_extra.id,
"payment_journal_id": cls.journal_reconciliation.id,
"transitory_account_id": cls.account_selfinvoice.id,
}
)

cls.rc_type_exempt = rc_type_model.create(
{
"name": "Intra EU (exempt)",
Expand Down Expand Up @@ -255,6 +282,14 @@ def _create_rc_type_taxes(cls):
}
)

cls.rc_type_tax_eeu_no_selfinvoice_extra = rc_type_tax_model.create(
SirAionTech marked this conversation as resolved.
Show resolved Hide resolved
{
"rc_type_id": cls.rc_type_eeu_no_selfinvoice_extra.id,
"purchase_tax_id": cls.tax_22ae.id,
"sale_tax_id": cls.tax_22ve.id,
}
)

cls.rc_type_tax_exempt = rc_type_tax_model.create(
{
"rc_type_id": cls.rc_type_exempt.id,
Expand All @@ -274,6 +309,24 @@ def _create_fiscal_position(cls):
{"name": "Extra EU", "rc_type_id": cls.rc_type_eeu.id}
)

cls.fiscal_position_extra_no_si = model_fiscal_position.create(
{
"name": "Extra EU no extra self invoice",
"rc_type_id": cls.rc_type_eeu_no_selfinvoice_extra.id,
}
)

cls.fiscal_position_exempt = model_fiscal_position.create(
{"name": "Intra EU exempt", "rc_type_id": cls.rc_type_exempt.id}
)

@classmethod
def _create_currency_rate(cls, currency_id, rate, date="2016-01-01"):
cls.env["res.currency.rate"].create(
{
"name": date,
"currency_id": currency_id,
"rate": rate,
"company_id": cls.env.company.id,
}
)
47 changes: 47 additions & 0 deletions l10n_it_reverse_charge/tests/test_rc.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,53 @@ def test_supplier_extraEU_no_outstanding_payment(self):
payments_lines = (self_purchase_payment | self_purchase_rc_payment).line_ids
self.assertTrue(all(payments_lines.mapped("reconciled")))

def test_supplier_extraEU_no_outstanding_payment_different_currencies(self):
"""
Self invoice from Extra EU partner in a different currency
"""
invoice = self.create_invoice(
self.supplier_extraEU_EUR,
amounts=[100],
taxes=self.tax_22ae,
currency=self.env.ref("base.EUR"),
)

self_invoice = invoice.rc_self_invoice_id
self_payment = self_invoice.rc_payment_move_id
# check self payment creation
self.assertTrue(self_payment)
# check self payment amount total
self.assertEqual(self_payment.amount_total, 144.0)
# check self payment amount total in currency
self.assertEqual(self_payment.amount_total_signed, 130.91)
# check self payment lines amount currency setting
self.assertTrue(all(self_payment.line_ids.mapped("amount_currency")))

# check self invoice amount
invoices_amounts_sum = (
invoice.amount_untaxed_signed + self_invoice.amount_untaxed_signed
)
self.assertEqual(invoices_amounts_sum, 0.0)

# check amount conversion
invoice_amount_untaxed_usd = invoice.currency_id._convert(
invoice.amount_untaxed,
invoice.company_id.currency_id,
invoice.company_id,
invoice.invoice_date,
)
self_invoice_test_line = self_invoice.line_ids.filtered(
lambda x: x.name == "test line"
)
self.assertEqual(
invoice_amount_untaxed_usd, abs(self_invoice_test_line.balance)
)

# check amount_currency setting
self.assertEqual(
invoice.amount_untaxed, abs(self_invoice_test_line.amount_currency)
)

def test_extra_EU_draft_and_reconfirm(self):
"""Check that an invoice with RC Self Purchase Invoice
can be reset to draft and confirmed again."""
Expand Down
Loading