# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime as dt import unittest from collections import defaultdict from contextlib import contextmanager from unittest.mock import patch from trytond.model import ModelStorage, ModelView from trytond.modules.company.model import CompanyMultiValueMixin from trytond.modules.currency.tests import add_currency_rate, create_currency from trytond.modules.party.tests import ( PartyCheckEraseMixin, PartyCheckReplaceMixin) from trytond.pool import Pool, isregisteredby from trytond.pyson import Eval, PYSONEncoder from trytond.tests.test_tryton import ModuleTestCase, with_transaction from trytond.tools import timezone as tz from trytond.transaction import Transaction def create_company(name='Dunder Mifflin', currency=None): pool = Pool() Party = pool.get('party.party') Company = pool.get('company.company') if currency is None: currency = create_currency('usd') add_currency_rate(currency, 1) party, = Party.create([{ 'name': name, 'addresses': [('create', [{}])], }]) company = Company(party=party, currency=currency) company.save() return company def create_employee(company, name="Pam Beesly"): pool = Pool() Party = pool.get('party.party') Employee = pool.get('company.employee') party, = Party.create([{ 'name': name, 'addresses': [('create', [{}])], }]) employee = Employee(party=party, company=company) employee.save() return employee @contextmanager def set_company(company): pool = Pool() User = pool.get('res.user') User.write([User(Transaction().user)], { 'companies': [('add', [company.id])], 'company': company.id, }) with Transaction().set_context(User.get_preferences(context_only=True)): yield class PartyCompanyCheckEraseMixin(PartyCheckEraseMixin): def setup_check_erase_party(self): create_company() return super().setup_check_erase_party() class CompanyTestMixin: @with_transaction() def test_company_multivalue_context(self): "Test context of company multivalue target" pool = Pool() Company = pool.get('company.company') for mname, model in pool.iterobject(): if (not isregisteredby(model, self.module) or issubclass(model, Company)): continue company = None for fname, field in model._fields.items(): if (field._type == 'many2one' and issubclass(field.get_target(), Company)): company = fname break else: continue for fname, field in model._fields.items(): if not hasattr(field, 'get_target'): continue Target = field.get_target() if not issubclass(Target, CompanyMultiValueMixin): continue if company in model._fields: self.assertIn( 'company', list(field.context.keys()), msg="Missing '%s' value as company " 'in "%s"."%s" context' % ( company, mname, fname)) @property def _skip_company_rule(self): """Return a set of couple field name and model name for which no company rules are needed.""" return { ('company.employee', 'company'), ('res.user', 'company'), } @with_transaction() def test_company_rule(self): "Test missing company rule" pool = Pool() Rule = pool.get('ir.rule') Company = pool.get('company.company') to_check = defaultdict(set) for mname, model in pool.iterobject(): if (not isregisteredby(model, self.module) or model.__access__ or not (issubclass(model, ModelView) and issubclass(model, ModelStorage))): continue for fname, field in model._fields.items(): if (mname, fname) in self._skip_company_rule: continue if (field._type == 'many2one' and issubclass(field.get_target(), Company)): to_check[fname].add(mname) for fname, models in to_check.items(): rules = Rule.search([ ('rule_group', 'where', [ ('model', 'in', list(models)), ('global_p', '=', True), ('perm_read', '=', True), ]), ('domain', '=', PYSONEncoder(sort_keys=True).encode( [(fname, 'in', Eval('companies', []))])), ]) with_rules = {r.rule_group.model for r in rules} self.assertGreaterEqual(with_rules, models, msg='Models %(models)s are missing a global rule ' 'for field "%(field)s"' % { 'models': ', '.join( f'"{m}"' for m in (models - with_rules)), 'field': fname, }) class CompanyTestCase( PartyCompanyCheckEraseMixin, PartyCheckReplaceMixin, CompanyTestMixin, ModuleTestCase): 'Test Company module' module = 'company' @with_transaction() def test_company(self): 'Create company' company = create_company() self.assertTrue(company) @with_transaction() def test_employe(self): 'Create employee' pool = Pool() Party = pool.get('party.party') Employee = pool.get('company.employee') company1 = create_company() party, = Party.create([{ 'name': 'Pam Beesly', }]) employee, = Employee.create([{ 'party': party.id, 'company': company1.id, }]) self.assertTrue(employee) @with_transaction() def test_user_company(self): 'Test user company' pool = Pool() User = pool.get('res.user') transaction = Transaction() company1 = create_company() company2 = create_company('Michael Scott Paper Company', currency=company1.currency) company2.save() company3 = create_company() user1, user2 = User.create([{ 'name': 'Jim Halper', 'login': 'jim', 'companies': [('add', [company1.id, company2.id])], 'company': company1.id, }, { 'name': 'Pam Beesly', 'login': 'pam', 'companies': [('add', [company2.id])], 'company': company2.id, }]) self.assertTrue(user1) with transaction.set_user(user1.id): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.company, company1) self.assertEqual(user2.company, company2) with transaction.set_context({'company': company2.id}): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.company, company2) self.assertEqual(user2.company, company2) with transaction.set_context({'company': None}): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.company, None) self.assertEqual(user2.company, company2) with transaction.set_context(company=company3.id): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.company, None) self.assertEqual(user2.company, company2) @with_transaction() def test_user_root_company(self): "Test root user company" pool = Pool() User = pool.get('res.user') transaction = Transaction() company = create_company() root = User(0) root.company = None root.companies = None root.save() with transaction.set_user(0): with Transaction().set_context(company=company.id): root = User(0) self.assertEqual(root.company, company) @with_transaction() def test_user_employee(self): "Test user employee" pool = Pool() User = pool.get('res.user') transaction = Transaction() company = create_company() employee1 = create_employee(company, "Jim Halper") employee2 = create_employee(company, "Pam Bessly") employee3 = create_employee(company, "Michael Scott") user1, user2 = User.create([{ 'name': "Jim Halper", 'login': "jim", 'companies': [('add', [company.id])], 'company': company.id, 'employees': [('add', [employee1.id, employee2.id])], 'employee': employee1.id, }, { 'name': "Pam Beesly", 'login': "pam", 'companies': [('add', [company.id])], 'company': company.id, 'employees': [('add', [employee2.id])], 'employee': employee2.id, }]) with transaction.set_user(user1.id): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.employee, employee1) self.assertEqual(user2.employee, employee2) with transaction.set_context(employee=employee2.id): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.employee, employee2) self.assertEqual(user2.employee, employee2) with transaction.set_context(employee=None): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.employee, None) self.assertEqual(user2.employee, employee2) with transaction.set_context(employee=employee3.id): user1, user2 = User.browse([user1.id, user2.id]) self.assertEqual(user1.employee, None) self.assertEqual(user2.employee, employee2) @with_transaction() def test_user_root_employee(self): "Test root user employee" pool = Pool() User = pool.get('res.user') transaction = Transaction() company = create_company() employee = create_employee(company, "Jim Halper") root = User(0) root.employee = None root.employees = None root.save() with transaction.set_user(0): with Transaction().set_context(employee=employee.id): root = User(0) self.assertEqual(root.employee, employee) @with_transaction() def test_company_header(self): "Test company header" company = create_company() company.party.email = 'company@example.com' company.party.save() company.header = "${name} - ${email}" company.save() self.assertEqual( company.header_used, "Dunder Mifflin - company@example.com") @with_transaction() def test_company_footer(self): "Test company footer" company = create_company() company.party.email = 'company@example.com' company.party.save() company.footer = "${name} - ${email}" company.save() self.assertEqual( company.footer_used, "Dunder Mifflin - company@example.com") @with_transaction() def test_employee_active_no_dates(self): "Test employee active with dates" pool = Pool() Employee = pool.get('company.employee') company = create_company() employee = create_employee(company, "Jim Halper") self.assertEqual(employee.active, True) self.assertEqual(Employee.search([ ('active', '=', True), ]), [employee]) self.assertEqual(Employee.search([ ('active', '!=', False), ]), [employee]) self.assertEqual(Employee.search([ ('active', '=', False), ]), []) self.assertEqual(Employee.search([ ('active', '!=', True), ]), []) @with_transaction() def test_employee_active_start_date(self): "Test employee active with start date" pool = Pool() Employee = pool.get('company.employee') company = create_company() employee = create_employee(company, "Jim Halper") employee.start_date = dt.date.today() employee.save() with Transaction().set_context(date=employee.start_date): self.assertEqual(Employee(employee).active, True) self.assertEqual(Employee.search([ ('active', '=', True), ]), [employee]) with Transaction().set_context( date=employee.start_date - dt.timedelta(days=1)): self.assertEqual(Employee(employee).active, False) self.assertEqual(Employee.search([ ('active', '=', True), ]), []) with Transaction().set_context( date=employee.start_date + dt.timedelta(days=1)): self.assertEqual(Employee(employee).active, True) self.assertEqual(Employee.search([ ('active', '=', True), ]), [employee]) @with_transaction() def test_employee_active_end_date(self): "Test employee active with end date" pool = Pool() Employee = pool.get('company.employee') company = create_company() employee = create_employee(company, "Jim Halper") employee.end_date = dt.date.today() employee.save() with Transaction().set_context(date=employee.end_date): self.assertEqual(Employee(employee).active, True) self.assertEqual(Employee.search([ ('active', '=', True), ]), [employee]) with Transaction().set_context( date=employee.end_date - dt.timedelta(days=1)): self.assertEqual(Employee(employee).active, True) self.assertEqual(Employee.search([ ('active', '=', True), ]), [employee]) with Transaction().set_context( date=employee.end_date + dt.timedelta(days=1)): self.assertEqual(Employee(employee).active, False) self.assertEqual(Employee.search([ ('active', '=', True), ]), []) @unittest.skipUnless( 'CET' in tz.available_timezones(), "missing CET timezone") @with_transaction() def test_today(self): "Test today is using the timezone of the contextual company" pool = Pool() Date = pool.get('ir.date') company = create_company() company.timezone = 'CET' company.save() with patch('datetime.datetime') as datetime: with Transaction().set_context(company=company.id): Date.today() datetime.now.assert_called_with(tz.ZoneInfo('CET')) @with_transaction() def test_company_tax_identifier(self): "Test company tax identifier" pool = Pool() Country = pool.get('country.country') Organization = pool.get('country.organization') Identifier = pool.get('party.identifier') TaxIdentifier = pool.get('company.company.tax_identifier') company = create_company() fr_vat = Identifier( party=company.party, type='fr_vat', code="FR23334175221") fr_vat.save() be_vat = Identifier( party=company.party, type='be_vat', code="BE403019261") be_vat.save() belgium = Country(name="Belgium") belgium.save() france = Country(name="France") france.save() germany = Country(name="Germany") germany.save() switzerland = Country(name="Switzerland") switzerland.save() europe = Organization( name="Europe", members=[ {'country': belgium}, {'country': france}, {'country': germany}, ]) europe.save() TaxIdentifier.create([{ 'company': company, 'country': france, 'tax_identifier': fr_vat, }, { 'company': company, 'country': belgium, 'tax_identifier': be_vat, }, { 'company': company, 'organization': europe, 'tax_identifier': be_vat, }]) self.assertEqual(company.party.tax_identifier, fr_vat) self.assertEqual(company.get_tax_identifier({ 'country': france.id, }), fr_vat) self.assertEqual(company.get_tax_identifier({ 'country': belgium.id, }), be_vat) self.assertEqual(company.get_tax_identifier({ 'country': germany.id, }), be_vat) self.assertEqual(company.get_tax_identifier({ 'country': switzerland, }), fr_vat) del ModuleTestCase