diff options
| author | Nicolas Lempereur <nle@odoo.com> | 2025-01-23 20:01:58 +0100 |
|---|---|---|
| committer | Nicolas Lempereur <nle@odoo.com> | 2025-02-06 16:44:15 +0000 |
| commit | be11713fe02aa4f9fbff7528acb1fd408ad725cb (patch) | |
| tree | fb696d8c4361fe46c6967449fa55dad4550bebca | |
| parent | 0528b73ae97ef6d19592cc2232556c6acadc652d (diff) | |
[FIX] l10n_it_edi: post invoice w/ multiple downpayments
Scenario:
- create a sale order and confirm it
- create two partial down payments for that sale order and confirm them
- create a invoice for the remaining amount and confirm it
- send and print the invoice (with Send to Tax Agency selected)
Result:
Traceback error is raised:
> ...
> File "addons/account/models/account_tax.py", line 2475, in _dispatch_negative_lines
> line.setdefault('discount_amount', line['discount_amount_before_dispatching'])
> KeyError: 'discount_amount_before_dispatching'
Why:
bbe04fb62916ae326c830e89b2664dfd32b62b75 was modifying the list
base_lines while looping over it, so we would not iterate over all
elements, for example:
> l = [5, 6, 7, 8]
> for i in l: print(i);l.remove(i)
shows 5 and 7
Notes:
Without the fix, the added test fails with the error given above.
The same code is in 17.0 but doesn't cause this error because we have
two loops. One that sets 'discount_amount_before_dispatching' and after
that one that remove downpayment from base_lines. But the fix should
still be backported because it works by chance.
opw-4496310
closes odoo/odoo#194949
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
3 files changed, 149 insertions, 2 deletions
diff --git a/addons/l10n_it_edi/models/account_move.py b/addons/l10n_it_edi/models/account_move.py index b74b6e5b9c8..29926a206a4 100644 --- a/addons/l10n_it_edi/models/account_move.py +++ b/addons/l10n_it_edi/models/account_move.py @@ -507,7 +507,6 @@ class AccountMove(models.Model): line = base_line['record'] if line.price_subtotal < 0 and line._get_downpayment_lines(): downpayment_lines.append(base_line) - base_lines.remove(base_line) if float_compare(quantity, 0, 2) < 0: # Negative quantity is refused by SDI, so we invert quantity and price_unit to keep the price_subtotal @@ -515,6 +514,8 @@ class AccountMove(models.Model): 'quantity': -quantity, 'price_unit': -price_unit, }) + for downpayment_line in downpayment_lines: + base_lines.remove(downpayment_line) dispatched_results = self.env['account.tax']._dispatch_negative_lines(base_lines) base_lines = dispatched_results['result_lines'] + dispatched_results['orphan_negative_lines'] + downpayment_lines diff --git a/addons/l10n_it_edi/tests/export_xmls/test_export_invoice_with_two_downpayments.xml b/addons/l10n_it_edi/tests/export_xmls/test_export_invoice_with_two_downpayments.xml new file mode 100644 index 00000000000..c1f41b39115 --- /dev/null +++ b/addons/l10n_it_edi/tests/export_xmls/test_export_invoice_with_two_downpayments.xml @@ -0,0 +1,115 @@ +<?xml version='1.0' encoding='UTF-8'?> +<p:FatturaElettronica xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2" xsi:schemaLocation="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2 http://www.fatturapa.gov.it/export/fatturazione/sdi/fatturapa/v1.2/Schema_del_file_xml_FatturaPA_versione_1.2.xsd" versione="FPR12"> + <FatturaElettronicaHeader> + <DatiTrasmissione> + <IdTrasmittente> + <IdPaese>IT</IdPaese> + <IdCodice>01234560157</IdCodice> + </IdTrasmittente> + <ProgressivoInvio>V202500003</ProgressivoInvio> + <FormatoTrasmissione>FPR12</FormatoTrasmissione> + <CodiceDestinatario>0000000</CodiceDestinatario> + <ContattiTrasmittente> + <Telefono>0266766700</Telefono> + <Email>test@test.it</Email> + </ContattiTrasmittente> + </DatiTrasmissione> + <CedentePrestatore> + <DatiAnagrafici> + <IdFiscaleIVA> + <IdPaese>IT</IdPaese> + <IdCodice>01234560157</IdCodice> + </IdFiscaleIVA> + <CodiceFiscale>01234560157</CodiceFiscale> + <Anagrafica> + <Denominazione>company_2_data</Denominazione> + </Anagrafica> + <RegimeFiscale>RF01</RegimeFiscale> + </DatiAnagrafici> + <Sede> + <Indirizzo>1234 Test Street</Indirizzo> + <CAP>12345</CAP> + <Comune>Prova</Comune> + <Nazione>IT</Nazione> + </Sede> + </CedentePrestatore> + <CessionarioCommittente> + <DatiAnagrafici> + <IdFiscaleIVA> + <IdPaese>IT</IdPaese> + <IdCodice>00465840031</IdCodice> + </IdFiscaleIVA> + <CodiceFiscale>93026890017</CodiceFiscale> + <Anagrafica> + <Denominazione>Alessi</Denominazione> + </Anagrafica> + </DatiAnagrafici> + <Sede> + <Indirizzo>Via Privata Alessi 6</Indirizzo> + <CAP>28887</CAP> + <Comune>Milan</Comune> + <Nazione>IT</Nazione> + </Sede> + </CessionarioCommittente> + </FatturaElettronicaHeader> + <FatturaElettronicaBody> + <DatiGenerali> + <DatiGeneraliDocumento> + <TipoDocumento>TD01</TipoDocumento> + <Divisa>EUR</Divisa> + <Data>2025-02-03</Data> + <Numero>INV/2025/00003</Numero> + <ImportoTotaleDocumento>94.00</ImportoTotaleDocumento> + </DatiGeneraliDocumento> + <DatiFattureCollegate> + <IdDocumento>INV/2025/00001</IdDocumento> + <Data>2025-02-03</Data> + </DatiFattureCollegate> + <DatiFattureCollegate> + <IdDocumento>INV/2025/00002</IdDocumento> + <Data>2025-02-03</Data> + </DatiFattureCollegate> + </DatiGenerali> + <DatiBeniServizi> + <DettaglioLinee> + <NumeroLinea>1</NumeroLinea> + <Descrizione>Test Service Product</Descrizione> + <Quantita>1.00</Quantita> + <PrezzoUnitario>200.00000000</PrezzoUnitario> + <PrezzoTotale>200.00000000</PrezzoTotale> + <AliquotaIVA>22.00</AliquotaIVA> + </DettaglioLinee> + <DettaglioLinee> + <NumeroLinea>2</NumeroLinea> + <Descrizione>Down Payment (ref: INV/2025/00001 on 02/03/2025), INV/2025/00001</Descrizione> + <Quantita>1.00</Quantita> + <PrezzoUnitario>-40.98000000</PrezzoUnitario> + <PrezzoTotale>-40.98000000</PrezzoTotale> + <AliquotaIVA>22.00</AliquotaIVA> + </DettaglioLinee> + <DettaglioLinee> + <NumeroLinea>3</NumeroLinea> + <Descrizione>Down Payment (ref: INV/2025/00002 on 02/03/2025), INV/2025/00002</Descrizione> + <Quantita>1.00</Quantita> + <PrezzoUnitario>-81.97000000</PrezzoUnitario> + <PrezzoTotale>-81.97000000</PrezzoTotale> + <AliquotaIVA>22.00</AliquotaIVA> + </DettaglioLinee> + <DatiRiepilogo> + <AliquotaIVA>22.00</AliquotaIVA> + <ImponibileImporto>77.05</ImponibileImporto> + <Imposta>16.95</Imposta> + <EsigibilitaIVA>I</EsigibilitaIVA> + </DatiRiepilogo> + </DatiBeniServizi> + <DatiPagamento> + <CondizioniPagamento>TP02</CondizioniPagamento> + <DettaglioPagamento> + <ModalitaPagamento>MP05</ModalitaPagamento> + <DataScadenzaPagamento>2025-02-03</DataScadenzaPagamento> + <ImportoPagamento>94.00</ImportoPagamento> + <CodicePagamento>INV/2025/00003</CodicePagamento> + </DettaglioPagamento> + </DatiPagamento> + </FatturaElettronicaBody> +</p:FatturaElettronica> diff --git a/addons/l10n_it_edi/tests/test_edi_export.py b/addons/l10n_it_edi/tests/test_edi_export.py index aa21b9db764..35506cb5bf1 100644 --- a/addons/l10n_it_edi/tests/test_edi_export.py +++ b/addons/l10n_it_edi/tests/test_edi_export.py @@ -1,7 +1,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import Command -from odoo.tests import tagged +from odoo.tests import freeze_time, tagged from odoo.addons.l10n_it_edi.tests.common import TestItEdi @@ -495,3 +495,34 @@ class TestItEdiExport(TestItEdi): }) invoice.action_post() self._assert_export_invoice(invoice, 'export_foreign_currency_global_discount.xml') + + @freeze_time("2025-02-03") + def test_export_invoice_with_two_downpayments(self): + if self.env['ir.module.module']._get('sale').state != 'installed': + self.skipTest("sale module is not installed") + + sale_order = self.env['sale.order'].with_company(self.company).create({ + 'partner_id': self.italian_partner_a.id, + 'order_line': [ + Command.create({'product_id': self.service_product.id, 'price_unit': 200.00}), + ], + }) + sale_order.action_confirm() + + for amount in (50, 100): + self.env['account.move'].with_company(self.company).browse( + self.env['sale.advance.payment.inv'].create([{ + 'advance_payment_method': 'fixed', + 'fixed_amount': amount, + 'sale_order_ids': [Command.link(sale_order.id)], + }]).create_invoices()['res_id'] + ).action_post() + + invoice = self.env['account.move'].with_company(self.company).browse( + self.env['sale.advance.payment.inv'].create([{ + 'advance_payment_method': 'delivered', + 'sale_order_ids': [Command.link(sale_order.id)], + }]).create_invoices()['res_id'] + ) + invoice.action_post() + self._assert_export_invoice(invoice, 'test_export_invoice_with_two_downpayments.xml') |
