diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py index 9f9a6fc3820..728a72727cb 100644 --- a/addons/purchase/models/account_invoice.py +++ b/addons/purchase/models/account_invoice.py @@ -53,8 +53,12 @@ class AccountMove(models.Model): # Copy purchase lines. po_lines = self.purchase_id.order_line - self.line_ids.mapped('purchase_line_id') new_lines = self.env['account.move.line'] + sequence = max(self.line_ids.mapped('sequence')) + 1 if self.line_ids else 10 for line in po_lines.filtered(lambda l: not l.display_type): - new_line = new_lines.new(line._prepare_account_move_line(self)) + line_vals = line._prepare_account_move_line(self) + line_vals.update({'sequence': sequence}) + new_line = new_lines.new(line_vals) + sequence += 1 new_line.account_id = new_line._get_computed_account() new_line._onchange_price_subtotal() new_lines += new_line diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 3a03207fff5..c1d37b4db3f 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -541,6 +541,7 @@ class PurchaseOrder(models.Model): # 1) Prepare invoice vals and clean-up the section lines invoice_vals_list = [] + sequence = 10 for order in self: if order.invoice_status != 'to invoice': continue @@ -556,9 +557,15 @@ class PurchaseOrder(models.Model): continue if not float_is_zero(line.qty_to_invoice, precision_digits=precision): if pending_section: - invoice_vals['invoice_line_ids'].append((0, 0, pending_section._prepare_account_move_line())) + line_vals = pending_section._prepare_account_move_line() + line_vals.update({'sequence': sequence}) + invoice_vals['invoice_line_ids'].append((0, 0, line_vals)) + sequence += 1 pending_section = None - invoice_vals['invoice_line_ids'].append((0, 0, line._prepare_account_move_line())) + line_vals = line._prepare_account_move_line() + line_vals.update({'sequence': sequence}) + invoice_vals['invoice_line_ids'].append((0, 0, line_vals)) + sequence += 1 invoice_vals_list.append(invoice_vals) if not invoice_vals_list: diff --git a/addons/purchase/tests/test_purchase_invoice.py b/addons/purchase/tests/test_purchase_invoice.py index e3fbb8ccd39..630397b7d7a 100644 --- a/addons/purchase/tests/test_purchase_invoice.py +++ b/addons/purchase/tests/test_purchase_invoice.py @@ -327,3 +327,75 @@ class TestPurchaseToInvoice(AccountTestInvoicingCommon): aml = self.env['account.move.line'].search([('purchase_line_id', '=', purchase_order.order_line.id)]) self.assertRecordValues(aml, [{'analytic_account_id': analytic_account_manual.id}]) + + def test_sequence_invoice_lines_from_multiple_purchases(self): + """Test if the invoice lines are sequenced by purchase order when creating an invoice + from multiple selected po's""" + purchase_orders = self.env['purchase.order'] + + for _ in range(3): + pol_vals = [ + (0, 0, { + 'name': self.product_order.name, + 'product_id': self.product_order.id, + 'product_qty': 10.0, + 'product_uom': self.product_order.uom_id.id, + 'price_unit': self.product_order.list_price, + 'taxes_id': False, + 'sequence': sequence_number, + }) for sequence_number in range(10, 13)] + purchase_order = self.env['purchase.order'].with_context(tracking_disable=True).create({ + 'partner_id': self.partner_a.id, + 'order_line': pol_vals, + }) + purchase_order.button_confirm() + purchase_orders |= purchase_order + + action = purchase_orders.action_create_invoice() + invoice = self.env['account.move'].browse(action['res_id']) + + expected_purchase = [ + purchase_orders[0], purchase_orders[0], purchase_orders[0], + purchase_orders[1], purchase_orders[1], purchase_orders[1], + purchase_orders[2], purchase_orders[2], purchase_orders[2], + ] + for line in invoice.invoice_line_ids.sorted('sequence'): + self.assertEqual(line.purchase_order_id, expected_purchase.pop(0)) + + def test_sequence_autocomplete_invoice(self): + """Test if the invoice lines are sequenced by purchase order when using the autocomplete + feature on a bill to add lines from po's""" + purchase_orders = self.env['purchase.order'] + + for _ in range(3): + pol_vals = [ + (0, 0, { + 'name': self.product_order.name, + 'product_id': self.product_order.id, + 'product_qty': 10.0, + 'product_uom': self.product_order.uom_id.id, + 'price_unit': self.product_order.list_price, + 'taxes_id': False, + 'sequence': sequence_number, + }) for sequence_number in range(10, 13)] + purchase_order = self.env['purchase.order'].with_context(tracking_disable=True).create({ + 'partner_id': self.partner_a.id, + 'order_line': pol_vals, + }) + purchase_order.button_confirm() + purchase_orders |= purchase_order + + move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + PurchaseBillUnion = self.env['purchase.bill.union'] + move_form.purchase_vendor_bill_id = PurchaseBillUnion.browse(-purchase_orders[0].id) + move_form.purchase_vendor_bill_id = PurchaseBillUnion.browse(-purchase_orders[1].id) + move_form.purchase_vendor_bill_id = PurchaseBillUnion.browse(-purchase_orders[2].id) + invoice = move_form.save() + + expected_purchase = [ + purchase_orders[0], purchase_orders[0], purchase_orders[0], + purchase_orders[1], purchase_orders[1], purchase_orders[1], + purchase_orders[2], purchase_orders[2], purchase_orders[2], + ] + for line in invoice.invoice_line_ids.sorted('sequence'): + self.assertEqual(line.purchase_order_id, expected_purchase.pop(0))