diff --git a/addons/l10n_it_stock_ddt/models/account_invoice.py b/addons/l10n_it_stock_ddt/models/account_invoice.py index 0f160b49bf6..66ea2340d92 100644 --- a/addons/l10n_it_stock_ddt/models/account_invoice.py +++ b/addons/l10n_it_stock_ddt/models/account_invoice.py @@ -31,11 +31,11 @@ class AccountMove(models.Model): invoice_line_pickings.setdefault(done_moves_related.picking_id, []).append(line_count) else: total_invoices = done_moves_related.mapped('sale_line_id.invoice_lines').filtered( - lambda l: l.move_id.state == 'posted' and l.move_id.move_type == 'out_invoice').sorted(lambda l: l.move_id.invoice_date) + lambda l: l.move_id.state == 'posted' and l.move_id.move_type == 'out_invoice').sorted(lambda l: (l.move_id.invoice_date, l.move_id.id)) total_invs = [(i.product_uom_id._compute_quantity(i.quantity, i.product_id.uom_id), i) for i in total_invoices] inv = total_invs.pop(0) # Match all moves and related invoice lines FIFO looking for when the matched invoice_line matches line - for move in done_moves_related.sorted(lambda m: m.date): + for move in done_moves_related.sorted(lambda m: (m.date, m.id)): rounding = move.product_uom.rounding move_qty = move.product_qty while (float_compare(move_qty, 0, precision_rounding=rounding) > 0): diff --git a/addons/l10n_it_stock_ddt/tests/test_ddt.py b/addons/l10n_it_stock_ddt/tests/test_ddt.py index a09fe8d0b35..a13d074be05 100644 --- a/addons/l10n_it_stock_ddt/tests/test_ddt.py +++ b/addons/l10n_it_stock_ddt/tests/test_ddt.py @@ -100,3 +100,49 @@ class TestDDT(TestSaleCommon): # But is consistently broken after recent cleanings in sale # with the flush & invalidate, it always breaks, even without the cleanings # self.assertEqual(self.inv2.l10n_it_ddt_ids.ids, (pickx1 | pickx2).ids, 'DDTs should be linked to the invoice') + + def test_ddt_flow_2(self): + """ + Test that the link between the invoice lines and the deliveries linked to the invoice + through the link with the sale order is calculated correctly. + """ + so = self.env['sale.order'].create({ + 'partner_id': self.partner_a.id, + 'order_line': [(0, 0, { + 'product_id': self.product_a.id, + 'product_uom_qty': 3, + 'product_uom': self.product_a.uom_id.id, + 'price_unit': self.product_a.list_price, + 'tax_id': self.company_data['default_tax_sale'] + } + )], + 'pricelist_id': self.company_data['default_pricelist'].id, + 'picking_policy': 'direct', + }) + so.action_confirm() + + # deliver partially + picking_1 = so.picking_ids + picking_1.move_ids.write({'quantity_done': 1}) + wiz_act = picking_1.button_validate() + wiz = Form(self.env[wiz_act['res_model']].with_context(wiz_act['context'])).save() + wiz.process() + + invoice_1 = so._create_invoices() + invoice_form = Form(invoice_1) + with invoice_form.invoice_line_ids.edit(0) as line: + line.quantity = 1.0 + invoice_1 = invoice_form.save() + invoice_1.action_post() + + picking_2 = so.picking_ids.filtered(lambda p: p.state != 'done') + picking_2.move_ids.write({'quantity_done': 2}) + picking_2.button_validate() + + invoice_2 = so._create_invoices() + invoice_2.action_post() + + # Invalidate the cache to ensure the lines will be fetched in the right order. + picking_2.invalidate_model() + self.assertEqual(invoice_1.l10n_it_ddt_ids.ids, picking_1.ids, 'DDT picking_1 should be linked to the invoice_1') + self.assertEqual(invoice_2.l10n_it_ddt_ids.ids, picking_2.ids, 'DDT picking_2 should be linked to the invoice_2')