diff --git a/addons/sale/models/sale_order_line.py b/addons/sale/models/sale_order_line.py index f5800e87a53..fbe093a6e43 100644 --- a/addons/sale/models/sale_order_line.py +++ b/addons/sale/models/sale_order_line.py @@ -598,10 +598,11 @@ class SaleOrderLine(models.Model): 'discount': self.discount, 'price_unit': self.price_unit, 'tax_ids': [(6, 0, self.tax_id.ids)], - 'analytic_account_id': self.order_id.analytic_account_id.id, 'analytic_tag_ids': [(6, 0, self.analytic_tag_ids.ids)], 'sale_line_ids': [(4, self.id)], } + if self.order_id.analytic_account_id: + res['analytic_account_id'] = self.order_id.analytic_account_id.id if optional_values: res.update(optional_values) if self.display_type: diff --git a/addons/sale/tests/test_sale_to_invoice.py b/addons/sale/tests/test_sale_to_invoice.py index 6b4f5b5e809..b493e94cee4 100644 --- a/addons/sale/tests/test_sale_to_invoice.py +++ b/addons/sale/tests/test_sale_to_invoice.py @@ -405,3 +405,73 @@ class TestSaleToInvoice(TestSaleCommon): }) downpayment.create_invoices() self.assertEqual(so_for_downpayment.invoice_ids[0].company_id.id, so_company_id, "The company of the downpayment invoice should be the same as the one from the SO") + + def test_invoice_analytic_account_default(self): + """ Tests whether, when an analytic account rule is set and the so has no analytic account, + the default analytic acount is correctly computed in the invoice. + """ + analytic_account_default = self.env['account.analytic.account'].create({'name': 'default'}) + + self.env['account.analytic.default'].create({ + 'analytic_id': analytic_account_default.id, + 'product_id': self.product_a.id, + }) + + so_form = Form(self.env['sale.order']) + so_form.partner_id = self.partner_a + + with so_form.order_line.new() as sol: + sol.product_id = self.product_a + sol.product_uom_qty = 1 + + so = so_form.save() + so.action_confirm() + so._force_lines_to_invoice_policy_order() + + so_context = { + 'active_model': 'sale.order', + 'active_ids': [so.id], + 'active_id': so.id, + 'default_journal_id': self.company_data['default_journal_sale'].id, + } + down_payment = self.env['sale.advance.payment.inv'].with_context(so_context).create({}) + down_payment.create_invoices() + + aml = self.env['account.move.line'].search([('move_id', 'in', so.invoice_ids.ids)])[0] + self.assertRecordValues(aml, [{'analytic_account_id': analytic_account_default.id}]) + + def test_invoice_analytic_account_so_not_default(self): + """ Tests whether, when an analytic account rule is set and the so has an analytic account, + the default analytic acount doesn't replace the one from the so in the invoice. + """ + analytic_account_default = self.env['account.analytic.account'].create({'name': 'default'}) + analytic_account_so = self.env['account.analytic.account'].create({'name': 'so'}) + + self.env['account.analytic.default'].create({ + 'analytic_id': analytic_account_default.id, + 'product_id': self.product_a.id, + }) + + so_form = Form(self.env['sale.order']) + so_form.partner_id = self.partner_a + so_form.analytic_account_id = analytic_account_so + + with so_form.order_line.new() as sol: + sol.product_id = self.product_a + sol.product_uom_qty = 1 + + so = so_form.save() + so.action_confirm() + so._force_lines_to_invoice_policy_order() + + so_context = { + 'active_model': 'sale.order', + 'active_ids': [so.id], + 'active_id': so.id, + 'default_journal_id': self.company_data['default_journal_sale'].id, + } + down_payment = self.env['sale.advance.payment.inv'].with_context(so_context).create({}) + down_payment.create_invoices() + + aml = self.env['account.move.line'].search([('move_id', 'in', so.invoice_ids.ids)])[0] + self.assertRecordValues(aml, [{'analytic_account_id': analytic_account_so.id}]) diff --git a/addons/sale_project/models/sale_order.py b/addons/sale_project/models/sale_order.py index 9e7e7be805e..83d956403a9 100644 --- a/addons/sale_project/models/sale_order.py +++ b/addons/sale_project/models/sale_order.py @@ -357,7 +357,7 @@ class SaleOrderLine(models.Model): to this sale order line, or the analytic account of the project which uses this sale order line, if it exists. """ values = super(SaleOrderLine, self)._prepare_invoice_line(**optional_values) - if not values['analytic_account_id']: + if not values.get('analytic_account_id'): if self.task_id.analytic_account_id: values['analytic_account_id'] = self.task_id._get_task_analytic_account_id().id elif self.project_id.analytic_account_id: