Files
enterprise-addons/account_inter_company_rules/tests/test_inter_company_invoice.py
T

298 lines
15 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import Command, tests
from .common import TestInterCompanyRulesCommon
@tests.tagged('post_install', '-at_install')
class TestInterCompanyInvoice(TestInterCompanyRulesCommon):
@classmethod
def setUpClass(cls):
super(TestInterCompanyInvoice, cls).setUpClass()
# Enable auto generate invoice in company.
(cls.company_a + cls.company_b).write({
'intercompany_generate_bills_refund': True,
})
# Configure Chart of Account for company_b.
cls.env.user.company_id = cls.company_b
cls.env['account.chart.template'].try_loading('generic_coa', cls.company_b, install_demo=False)
# Configure Chart of Account for company_a.
cls.env.user.company_id = cls.company_a
cls.env['account.chart.template'].try_loading('generic_coa', cls.company_a, install_demo=False)
def _configure_analytic(self, product=None, company=None, partner=None):
"""
Configure Analytic Distribution Model for company_a based on Product A
return: analytic account
"""
display_name = "Inter Company"
if company:
self.env.user.company_id = company
display_name = company.display_name
analytic_plan = self.env['account.analytic.plan'].create({'name': f'Analytic Plan {display_name}'})
analytic_account = self.env['account.analytic.account'].create({
'name': f'Account {display_name}',
'company_id': company and company.id,
'plan_id': analytic_plan.id,
})
self.env['account.analytic.distribution.model'].create({
'analytic_distribution': {analytic_account.id: 100},
'product_id': product and product.id,
'company_id': company and company.id,
'partner_id': partner and partner.id,
})
return analytic_account
def _create_post_invoice(self, product_id, analytic_distribution=None):
"""Create a Company A invoice with Company B as the customer and post it"""
invoice_line_vals = {
'product_id': product_id,
'price_unit': 100.0,
'quantity': 1.0,
}
if analytic_distribution:
invoice_line_vals['analytic_distribution'] = analytic_distribution
customer_invoice = self.env['account.move'].with_user(self.res_users_company_a).create({
'move_type': 'out_invoice',
'partner_id': self.company_b.partner_id.id,
'invoice_line_ids': [(0, 0, invoice_line_vals)]
})
customer_invoice.with_user(self.res_users_company_a).action_post()
def test_00_inter_company_invoice_flow(self):
""" Test inter company invoice flow """
self.env.ref('base.EUR').active = True
# Create customer invoice for company A. (No need to call onchange as all the needed values are specified)
self.res_users_company_a.company_ids = [(4, self.company_b.id)]
customer_invoice = self.env['account.move'].with_user(self.res_users_company_a).create({
'move_type': 'out_invoice',
'partner_id': self.company_b.partner_id.id,
'currency_id': self.env.ref('base.EUR').id,
'invoice_line_ids': [(0, 0, {
'product_id': self.product_consultant.id,
'price_unit': 450.0,
'quantity': 1.0,
'name': 'test'
})]
})
# Check account invoice state should be draft.
self.assertEqual(customer_invoice.state, 'draft', 'Initially customer invoice should be in the "Draft" state')
# Validate invoice
customer_invoice.with_user(self.res_users_company_a).action_post()
# Check Invoice status should be open after validate.
self.assertEqual(customer_invoice.state, 'posted', 'Invoice should be in Open state.')
# I check that the vendor bill is created with proper data.
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertTrue(supplier_invoice.invoice_line_ids[0].quantity == 1, "Quantity in invoice line is incorrect.")
self.assertTrue(supplier_invoice.invoice_line_ids[0].product_id.id == self.product_consultant.id, "Product in line is incorrect.")
self.assertTrue(supplier_invoice.invoice_line_ids[0].price_unit == 450, "Unit Price in invoice line is incorrect.")
self.assertTrue(supplier_invoice.invoice_line_ids[0].account_id.company_ids == self.company_b, "Applied account in created invoice line is not relevant to company.")
self.assertTrue(supplier_invoice.state == "draft", "invoice should be in draft state.")
self.assertEqual(supplier_invoice.amount_total, 517.5, "Total amount is incorrect.")
self.assertTrue(supplier_invoice.company_id.id == self.company_b.id, "Applied company in created invoice is incorrect.")
def test_default_analytic_distribution_company_b(self):
"""
[Analytic Distribution Model is set for Company B + Inter Company Analytic Account is set]
- With Company A, create an Invoice for Company B with product A set with an analytic distribution model available for Company B
-> The Analytic Distribution set on the Supplier Invoice Line should be the same as defined in the analytic distribution model set by default for Company B
and the one manually set when the analytic account is also available for Company B
"""
analytic_account_company_b = self._configure_analytic(company=self.company_b, product=self.product_a)
inter_company_analytic_account = self._configure_analytic(product=self.product_b)
self._create_post_invoice(product_id=self.product_a.id, analytic_distribution={inter_company_analytic_account.id: 100})
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertEqual(supplier_invoice.invoice_line_ids.analytic_distribution, {str(analytic_account_company_b.id): 100, str(inter_company_analytic_account.id): 100})
def test_no_default_analytic_distribution_company_b(self):
"""
[Analytic Distribution Model is not set for Company B + Inter Company Analytic Account is set]
- With Company A, create an Invoice for Company B with a line set with an analytic distribution model available for Company B
-> The analytic distribution set on the supplier invoice line should be the same as defined in the customer invoice line created in Company A
as the analytic account is available for Company B and there are no default analytic distribution model set for Company B
"""
inter_company_analytic_account = self._configure_analytic(product=self.product_b)
self._create_post_invoice(product_id=self.product_a.id, analytic_distribution={inter_company_analytic_account.id: 100})
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertEqual(supplier_invoice.invoice_line_ids.analytic_distribution, {str(inter_company_analytic_account.id): 100})
def test_multi_analytic_account_distribution_company_b(self):
"""
Test that the analytic distribution is set properly when multiple analytic accounts (with or without a company) are set on the invoice line
"""
analytic_account_company_a = self._configure_analytic(company=self.company_a, product=self.product_a)
inter_company_analytic_account = self._configure_analytic(product=self.product_a)
self._create_post_invoice(product_id=self.product_a.id, analytic_distribution={
analytic_account_company_a.id: 50,
inter_company_analytic_account.id: 50,
f"{analytic_account_company_a.id},{inter_company_analytic_account.id}": 100
})
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertEqual(supplier_invoice.invoice_line_ids.analytic_distribution, {str(inter_company_analytic_account.id): 50})
def test_default_analytic_distribution_company_a(self):
"""
[Analytic Distribution Model is set for Company A]
- With Company A, create an Invoice for Company B with a line set with an analytic distribution model not available for Company B
-> There should be no analytic distribution set on the supplier invoice line as there is no analytic distribution model available for Company B
and the analytic account is not available for Company B
"""
analytic_account_company_a = self._configure_analytic(company=self.company_a, product=self.product_a)
self._create_post_invoice(product_id=self.product_a.id, analytic_distribution={analytic_account_company_a.id: 100})
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertFalse(supplier_invoice.invoice_line_ids.analytic_distribution, "Analytic distribution should not be set on the invoice line.")
def test_inter_company_invoice_flow_sub_companies(self):
"""
Test that the flow with inter company invoice is also working properly with sub companies
"""
# Create branches for company a
self.company_a.write({'child_ids': [
Command.create({'name': 'Branch 1 of company a'}),
Command.create({'name': 'Branch 2 of company a'}),
]})
self.cr.precommit.run() # load the COA
branch_1, branch_2 = self.company_a.child_ids
(branch_1 + branch_2).write({
'intercompany_generate_bills_refund': True,
})
# It's required to have an intercompany_journal_id set to be able to do the generation
for branch in [branch_1, branch_2]:
branch.intercompany_purchase_journal_id = self.env['account.journal'].create({
'name': 'Purchases - Test',
'code': 'TEXJ',
'type': 'purchase',
'company_id': branch.id,
})
# Select the two branches
self.env.user.write({
'company_ids': [Command.set((branch_1 + branch_2).ids)],
'company_id': branch_1.id,
})
# Invoice from Branch 1 to Branch 2
customer_invoice = self.env['account.move'].with_context(allowed_company_ids=branch_1.ids).create({
'move_type': 'out_invoice',
'invoice_date': '2023-05-01',
'partner_id': branch_2.partner_id.id,
'invoice_line_ids': [Command.create({
'product_id': self.product_a.id,
'price_unit': 100.0,
'quantity': 1.0,
'tax_ids': False,
})]
})
customer_invoice.action_post()
bill = self.env['account.move'].search([('move_type', '=', 'in_invoice')], limit=1)
self.assertRecordValues(bill, [{
'partner_id': branch_1.partner_id.id,
'company_id': branch_2.id,
'payment_reference': customer_invoice.payment_reference,
}])
def test_inter_company_invoice_product_not_accessible(self):
"""
Whenever Company A invoices Company B with a Product A defined only for Company A
We don't set Product A (access error) but we define only the invoice line's label
with Product A's name
"""
self.product_a.company_id = self.company_a
self._create_post_invoice(self.product_a.id)
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
self.assertFalse(supplier_invoice.invoice_line_ids.product_id, "No product should be set")
self.assertEqual(supplier_invoice.invoice_line_ids.name, self.product_a.name)
def test_analytic_distribution_model_partner(self):
"""
If company B defines Company A as a partner in its distribution model, the distribution should be retrieved
"""
inter_company_analytic_account = self._configure_analytic(product=self.product_b)
analytic_account_company_b = self._configure_analytic(company=self.company_b, partner=self.company_a.partner_id)
self._create_post_invoice(product_id=self.product_a.id, analytic_distribution={inter_company_analytic_account.id: 100})
supplier_invoice = self.env['account.move'].with_user(self.res_users_company_b).search([('move_type', '=', 'in_invoice')], limit=1)
expected_distribution = {
str(inter_company_analytic_account.id): 100,
str(analytic_account_company_b.id): 100
}
self.assertEqual(supplier_invoice.invoice_line_ids.analytic_distribution, expected_distribution)
def test_inter_company_attachment_with_contact_as_partner(self):
"""
Test that when creating and printing an invoice in company A for an individual contact belonging to company B,
the corresponding bill in company B there is an attachment.
"""
company_partner = self.env['res.partner'].create({
'name': 'company partner',
'parent_id': self.company_b.partner_id.id,
})
customer_invoice = self.env['account.move'].create({
'company_id': self.company_a.id,
'move_type': 'out_invoice',
'invoice_date': '2023-05-01',
'partner_id': company_partner.id,
'invoice_line_ids': [Command.create({
'product_id': self.product_a.id,
'price_unit': 100.0,
'quantity': 1.0,
'tax_ids': False,
})]
})
customer_invoice.action_post()
self.env['account.move.send.wizard'].with_context(active_model='account.move', active_ids=customer_invoice.id)._generate_and_send_invoices(customer_invoice)
bill = self.env['account.move'].search([('move_type', '=', 'in_invoice'), ('company_id', '=', self.company_b.id)], limit=1)
self.assertTrue(bill.attachment_ids)
def test_inter_company_with_contact_as_partner_same_company(self):
"""
Test that when creating a bill in company A for an individual contact belonging to the same company A,
no invoice is created.
"""
company_partner = self.env['res.partner'].create({
'name': 'company partner',
'parent_id': self.company_a.partner_id.id,
})
customer_expense_bill = self.env['account.move'].create({
'company_id': self.company_a.id,
'move_type': 'in_invoice',
'invoice_date': '2023-05-01',
'partner_id': company_partner.id,
'invoice_line_ids': [Command.create({
'product_id': self.product_a.id,
'price_unit': 100.0,
'quantity': 1.0,
'tax_ids': False,
})]
})
customer_expense_bill.action_post()
invoice = self.env['account.move'].search([('move_type', '=', 'out_invoice'), ('company_id', '=', self.company_a.id)], limit=1)
self.assertFalse(invoice)