account/tests/test_company_branch.py

238 lines
10 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
from contextlib import nullcontext
from freezegun import freeze_time
from functools import partial
from odoo import Command
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.exceptions import UserError
from odoo.tests import tagged, Form
@tagged('post_install', '-at_install')
class TestCompanyBranch(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref)
cls.company_data['company'].write({
'child_ids': [
Command.create({'name': 'Branch A'}),
Command.create({'name': 'Branch B'}),
],
})
cls.cr.precommit.run() # load the CoA
cls.root_company = cls.company_data['company']
cls.branch_a, cls.branch_b = cls.root_company.child_ids
def test_chart_template_loading(self):
# Some company params have to be the same
self.assertEqual(self.root_company.currency_id, self.branch_a.currency_id)
self.assertEqual(self.root_company.fiscalyear_last_day, self.branch_a.fiscalyear_last_day)
self.assertEqual(self.root_company.fiscalyear_last_month, self.branch_a.fiscalyear_last_month)
# The accounts are shared
root_accounts = self.env['account.account'].search([('company_id', 'parent_of', self.root_company.id)])
branch_a_accounts = self.env['account.account'].search([('company_id', 'parent_of', self.branch_a.id)])
self.assertTrue(root_accounts)
self.assertEqual(root_accounts, branch_a_accounts)
# The journals are shared
root_journals = self.env['account.journal'].search([('company_id', 'parent_of', self.root_company.id)])
branch_a_journals = self.env['account.journal'].search([('company_id', 'parent_of', self.branch_a.id)])
self.assertTrue(root_journals)
self.assertEqual(root_journals, branch_a_journals)
def test_reconciliation(self):
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'invoice_date': '2016-01-01',
'company_id': self.branch_a.id,
'partner_id': self.partner_a.id,
'invoice_line_ids': [
Command.create({
'name': 'product',
'price_unit': 1000,
})
],
})
invoice.action_post()
refund = self.env['account.move'].create({
'move_type': 'out_refund',
'invoice_date': '2017-01-01',
'company_id': self.root_company.id,
'partner_id': self.partner_a.id,
'invoice_line_ids': [
Command.create({
'name': 'product',
'price_unit': 1000,
})
],
})
refund.action_post()
payment_lines = (invoice + refund).line_ids.filtered(lambda l: l.display_type == 'payment_term')
payment_lines.reconcile()
self.assertEqual(payment_lines.mapped('amount_residual'), [0, 0])
self.assertFalse(payment_lines.matched_debit_ids.exchange_move_id)
# Can still open the invoice with only it's branch accessible
self.env.invalidate_all()
with Form(invoice.with_context(allowed_company_ids=self.branch_a.ids)):
pass
def test_reconciliation_foreign_currency(self):
invoice = self.env['account.move'].create({
'move_type': 'out_invoice',
'invoice_date': '2016-01-01',
'company_id': self.branch_a.id,
'currency_id': self.currency_data['currency'].id,
'partner_id': self.partner_a.id,
'invoice_line_ids': [
Command.create({
'name': 'product',
'price_unit': 1000,
})
],
})
invoice.action_post()
refund = self.env['account.move'].create({
'move_type': 'out_refund',
'invoice_date': '2017-01-01',
'company_id': self.root_company.id,
'currency_id': self.currency_data['currency'].id,
'partner_id': self.partner_a.id,
'invoice_line_ids': [
Command.create({
'name': 'product',
'price_unit': 1000,
})
],
})
refund.action_post()
payment_lines = (invoice + refund).line_ids.filtered(lambda l: l.display_type == 'payment_term')
payment_lines.reconcile()
self.assertEqual(payment_lines.mapped('amount_residual'), [0, 0])
self.assertTrue(payment_lines.matched_debit_ids.exchange_move_id)
self.assertTrue(payment_lines.matched_debit_ids.exchange_move_id.journal_id.company_id, invoice.company_id)
# Can still open the invoice with only it's branch accessible
self.env.invalidate_all()
with Form(invoice.with_context(allowed_company_ids=self.branch_a.ids)):
pass
def test_lock_dates(self):
moves = self.env['account.move'].search([])
moves.filtered(lambda x: x.state != 'draft').button_draft()
moves.unlink()
for lock in ['fiscalyear_lock_date', 'tax_lock_date']:
for root_lock, branch_lock, invoice_date, company, expected in (
# before both locks
('3021-01-01', '3022-01-01', '3020-01-01', self.root_company, 'fail'),
('3021-01-01', '3022-01-01', '3020-01-01', self.branch_a, 'fail'),
# between root and branch lock
('3020-01-01', '3022-01-01', '3021-01-01', self.root_company, 'success'),
('3020-01-01', '3022-01-01', '3021-01-01', self.branch_a, 'fail'),
# between branch and root lock
('3022-01-01', '3020-01-01', '3021-01-01', self.root_company, 'fail'),
('3022-01-01', '3020-01-01', '3021-01-01', self.branch_a, 'fail'),
# after both locks
('3020-01-01', '3021-01-01', '3022-01-01', self.root_company, 'success'),
('3020-01-01', '3021-01-01', '3022-01-01', self.branch_a, 'success'),
):
with self.subTest(
lock=lock,
root_lock=root_lock,
branch_lock=branch_lock,
invoice_date=invoice_date,
company=company.name,
), self.env.cr.savepoint() as sp:
with freeze_time('4000-01-01'): # ensure we don't lock in the future
self.root_company[lock] = root_lock
self.branch_a[lock] = branch_lock
check = partial(self.assertRaises, UserError) if expected == 'fail' else nullcontext
with check():
self.init_invoice(
'out_invoice', amounts=[100], taxes=self.root_company.account_sale_tax_id,
invoice_date=invoice_date, post=True, company=company,
)
sp.close()
def test_change_record_company(self):
account = self.env['account.account'].create({
'name': 'volatile',
'code': 'vola',
'account_type': 'income',
'company_id': self.branch_a.id,
})
account_lines = [Command.create({
'account_id': account.id,
'name': 'name',
})]
tax = self.env['account.tax'].create({
'name': 'volatile',
})
tax_lines = [Command.create({
'account_id': self.root_company.account_journal_suspense_account_id.id,
'tax_ids': [Command.set(tax.ids)],
'name': 'name',
})]
for record, lines in (
(account, account_lines),
(tax, tax_lines),
):
with self.subTest(model=record._name):
self.env['account.move'].create({'company_id': self.branch_a.id, 'line_ids': lines})
# Can switch to main
record.company_id = self.root_company
# Can switch back
record.company_id = self.branch_a
# Can't use in main if owned by a branch
with self.assertRaisesRegex(UserError, 'belongs to another company'):
self.env['account.move'].create({'company_id': self.root_company.id, 'line_ids': lines})
# Can still switch to main
record.company_id = self.root_company
# Can use in main now
self.env['account.move'].create({'company_id': self.root_company.id, 'line_ids': lines})
# Can't switch back to branch if used in main
with self.assertRaisesRegex(UserError, 'journal items linked'):
record.company_id = self.branch_a
def test_branch_should_keep_parent_company_currency(self):
test_country = self.env['res.country'].create({
'name': 'Gold Country',
'code': 'zz',
'currency_id': self.currency_data['currency'].id
})
root_company = self.env['res.company'].create({
'name': 'Gold Company',
'country_id': test_country.id,
})
# with the generic_coa, try_loading forces currency_id to USD and account_fiscal_country_id to United States
self.env['account.chart.template'].try_loading('generic_coa', company=root_company, install_demo=False)
# So we write these values after try_loading
root_company.write({
'currency_id': test_country.currency_id.id,
'account_fiscal_country_id': test_country.id,
})
root_company.write({
'child_ids': [
Command.create({
'name': 'Gold Branch',
'country_id': test_country.id,
}),
],
})
self.env['account.chart.template'].try_loading('generic_coa', company=root_company.child_ids[0], install_demo=False)
self.assertEqual(root_company.currency_id, root_company.child_ids[0].currency_id)