Skip to content

Commit b84d509

Browse files
committed
[FIX] l10n_it_split_payment: multi-taxes
1 parent b8c51df commit b84d509

File tree

3 files changed

+164
-58
lines changed

3 files changed

+164
-58
lines changed

l10n_it_split_payment/models/account_move.py

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
# Copyright 2023 Giuseppe Borruso <gborruso@dinamicheaziendali.it>
55
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
66

7-
from odoo import Command, fields, models
7+
from odoo import Command, _, fields, models
8+
from odoo.exceptions import UserError
89
from odoo.tools import float_compare
910

1011

@@ -26,8 +27,6 @@ def _compute_amount(self):
2627
res = super()._compute_amount()
2728
for move in self:
2829
if move.split_payment:
29-
if move.is_purchase_document():
30-
continue
3130
if move.tax_totals:
3231
move.amount_sp = (
3332
move.tax_totals["amount_total"]
@@ -48,6 +47,8 @@ def write(self, vals):
4847
)
4948
if self.env.context.get("skip_split_payment_computation"):
5049
return res
50+
if "fiscal_position_id" in vals:
51+
self._compute_amount()
5152
self.compute_split_payment()
5253
container = {"records": self}
5354
self._check_balanced(container)
@@ -63,27 +64,81 @@ def copy(self, default=None):
6364
res = super().copy(default=default)
6465
return res
6566

67+
def _build_writeoff_line(self):
68+
self.ensure_one()
69+
70+
if not self.company_id.sp_account_id:
71+
raise UserError(
72+
_(
73+
"Please set 'Split Payment Write-off Account' field in"
74+
" accounting configuration"
75+
)
76+
)
77+
debit = 0
78+
credit = 0
79+
move_tax_lines = self.line_ids.filtered(
80+
lambda line: ((line.display_type == "tax") and (not line.is_split_payment))
81+
)
82+
for tax_line in move_tax_lines:
83+
debit += tax_line.credit
84+
credit += tax_line.debit
85+
if debit != 0 and credit != 0:
86+
if debit >= credit:
87+
debit = debit - credit
88+
credit = 0
89+
else:
90+
credit = credit - debit
91+
debit = 0
92+
93+
vals = {
94+
"name": _("Split Payment Write Off"),
95+
"partner_id": self.partner_id.id,
96+
"account_id": self.company_id.sp_account_id.id,
97+
"journal_id": self.journal_id.id,
98+
"date": self.invoice_date,
99+
"date_maturity": self.invoice_date,
100+
"price_unit": -debit + credit,
101+
"amount_currency": debit - credit,
102+
"debit": debit,
103+
"credit": credit,
104+
"display_type": "tax",
105+
"is_split_payment": True,
106+
}
107+
return vals
108+
66109
def compute_split_payment(self):
67110
for move in self:
111+
line_sp = fields.first(
112+
move.line_ids.filtered(lambda move_line: move_line.is_split_payment)
113+
)
68114
if move.split_payment:
69-
line_sp = fields.first(
70-
move.line_ids.filtered(lambda move_line: move_line.is_split_payment)
71-
)
72-
for line in move.line_ids:
73-
if line.display_type == "tax" and not line.is_split_payment:
74-
write_off_line_vals = line._build_writeoff_line()
75-
if line_sp:
76-
if (
77-
float_compare(
78-
line_sp.price_unit,
79-
write_off_line_vals["price_unit"],
80-
precision_rounding=move.currency_id.rounding,
81-
)
82-
!= 0
83-
):
84-
line_sp.write(write_off_line_vals)
85-
else:
86-
if move.amount_sp:
87-
move.with_context(
88-
skip_split_payment_computation=True
89-
).line_ids = [Command.create(write_off_line_vals)]
115+
write_off_line_vals = move._build_writeoff_line()
116+
if line_sp:
117+
if (
118+
float_compare(
119+
line_sp.price_unit,
120+
write_off_line_vals["price_unit"],
121+
precision_rounding=move.currency_id.rounding,
122+
)
123+
!= 0
124+
):
125+
line_sp.write(write_off_line_vals)
126+
else:
127+
if write_off_line_vals.get("price_unit"):
128+
move.with_context(
129+
skip_split_payment_computation=True
130+
).line_ids = [Command.create(write_off_line_vals)]
131+
elif line_sp:
132+
neutralize_vals = {
133+
"debit": 0.0,
134+
"credit": 0.0,
135+
"amount_currency": 0.0,
136+
"price_unit": 0.0,
137+
"tax_base_amount": 0.0,
138+
"tax_tag_ids": [(6, 0, [])],
139+
}
140+
move.with_context(
141+
skip_split_payment_computation=True,
142+
check_move_validity=False,
143+
).write({"line_ids": [Command.update(line_sp.id, neutralize_vals)]})
144+
move._sync_dynamic_lines(container={"records": move, "self": move})

l10n_it_split_payment/models/account_move_line.py

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# Copyright 2023 Giuseppe Borruso <gborruso@dinamicheaziendali.it>
55
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
66

7-
from odoo import _, api, fields, models
8-
from odoo.exceptions import UserError
7+
from odoo import api, fields, models
8+
from odoo.tools import frozendict
99

1010

1111
class AccountMoveLine(models.Model):
@@ -20,49 +20,40 @@ def _compute_is_split_payment(self):
2020
if line.account_id == line.company_id.sp_account_id:
2121
line.is_split_payment = True
2222

23-
def _build_writeoff_line(self):
24-
self.ensure_one()
25-
26-
if not self.move_id.company_id.sp_account_id:
27-
raise UserError(
28-
_(
29-
"Please set 'Split Payment Write-off Account' field in"
30-
" accounting configuration"
31-
)
32-
)
33-
vals = {
34-
"name": _("Split Payment Write Off"),
35-
"partner_id": self.move_id.partner_id.id,
36-
"account_id": self.move_id.company_id.sp_account_id.id,
37-
"journal_id": self.move_id.journal_id.id,
38-
"date": self.move_id.invoice_date,
39-
"date_maturity": self.move_id.invoice_date,
40-
"price_unit": -self.credit,
41-
"amount_currency": self.credit,
42-
"debit": self.credit,
43-
"credit": self.debit,
44-
"display_type": "tax",
45-
}
46-
if self.move_id.move_type == "out_refund":
47-
vals["amount_currency"] = -self.debit
48-
vals["debit"] = self.credit
49-
vals["credit"] = self.debit
50-
return vals
23+
def _compute_all_tax(self):
24+
res = None
25+
for line in self:
26+
res = super(AccountMoveLine, line)._compute_all_tax()
27+
new_compute_all_tax = {}
28+
for tax_key, tax_vals in line.compute_all_tax.items():
29+
if (
30+
tax_key.get("tax_repartition_line_id")
31+
and tax_key.get("display_type")
32+
and not tax_key.get("is_split_payment")
33+
):
34+
new_tax_key = dict(tax_key)
35+
new_tax_key["is_split_payment"] = False
36+
tax_key = frozendict(new_tax_key)
37+
new_compute_all_tax[tax_key] = tax_vals
38+
line.compute_all_tax = new_compute_all_tax
39+
return res
5140

5241
@api.model_create_multi
5342
def create(self, vals_list):
5443
lines = super().create(vals_list)
44+
move_computed = []
5545
for line in lines:
5646
if (
57-
line.display_type == "tax"
47+
line.move_id not in move_computed
48+
and line.display_type == "tax"
5849
and line.move_id.split_payment
59-
and line.move_id.is_sale_document(include_receipts=True)
6050
and not line.is_split_payment
6151
and not any(ml.is_split_payment for ml in line.move_id.line_ids)
6252
):
63-
write_off_line_vals = line._build_writeoff_line()
53+
write_off_line_vals = line.move_id._build_writeoff_line()
6454
line.move_id.line_ids = [(0, 0, write_off_line_vals)]
6555
line.move_id._sync_dynamic_lines(
6656
container={"records": line.move_id, "self": line.move_id}
6757
)
58+
move_computed.append(line.move_id)
6859
return lines

l10n_it_split_payment/tests/test_splitpayment.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,24 @@ def setUp(self):
2727
"amount": 22,
2828
}
2929
)
30+
self.tax10sp = self.tax_model.create(
31+
{
32+
"name": "10% SP",
33+
"amount": 10,
34+
}
35+
)
3036
self.tax22 = self.tax_model.create(
3137
{
3238
"name": "22%",
3339
"amount": 22,
3440
}
3541
)
42+
self.tax10 = self.tax_model.create(
43+
{
44+
"name": "10%",
45+
"amount": 10,
46+
}
47+
)
3648
self.sp_fp = self.fp_model.create(
3749
{
3850
"name": "Split payment",
@@ -42,7 +54,12 @@ def setUp(self):
4254
0,
4355
0,
4456
{"tax_src_id": self.tax22.id, "tax_dest_id": self.tax22sp.id},
45-
)
57+
),
58+
(
59+
0,
60+
0,
61+
{"tax_src_id": self.tax10.id, "tax_dest_id": self.tax10sp.id},
62+
),
4663
],
4764
}
4865
)
@@ -272,3 +289,46 @@ def test_balanced_lines(self):
272289
self.assertEqual(invoice.amount_total, 200)
273290
self.assertEqual(invoice.amount_residual, 200)
274291
self.assertEqual(invoice.amount_tax, 0)
292+
293+
def test_invoice_two_sp_taxes(self):
294+
self.assertTrue(self.tax22sp.is_split_payment)
295+
self.assertTrue(self.tax10sp.is_split_payment)
296+
invoice = self.move_model.with_context(default_move_type="out_invoice").create(
297+
{
298+
"invoice_date": self.recent_date,
299+
"partner_id": self.env.ref("base.res_partner_3").id,
300+
"journal_id": self.sales_journal.id,
301+
"fiscal_position_id": self.sp_fp.id,
302+
"move_type": "out_refund",
303+
"invoice_line_ids": [
304+
(
305+
0,
306+
0,
307+
{
308+
"name": "service",
309+
"account_id": self.a_sale.id,
310+
"quantity": 1,
311+
"price_unit": 100,
312+
"tax_ids": [(6, 0, {self.tax22sp.id})],
313+
},
314+
),
315+
(
316+
0,
317+
0,
318+
{
319+
"name": "service2",
320+
"account_id": self.a_sale.id,
321+
"quantity": 1,
322+
"price_unit": 100,
323+
"tax_ids": [(6, 0, {self.tax10sp.id})],
324+
},
325+
),
326+
],
327+
}
328+
)
329+
line_sp = invoice.line_ids.filtered(
330+
lambda line: line.account_id.id == self.company.sp_account_id.id
331+
)
332+
333+
self.assertTrue(len(line_sp) == 1)
334+
self.assertEqual(line_sp.credit, 32)

0 commit comments

Comments
 (0)