Files
tradon/modules/account/tests/test_module.py
2026-03-14 09:42:12 +00:00

2301 lines
88 KiB
Python

# 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
from decimal import Decimal
from dateutil.relativedelta import relativedelta
from trytond.exceptions import UserError
from trytond.model.exceptions import SQLConstraintError
from trytond.modules.account.exceptions import PeriodDatesError
from trytond.modules.account.tax import TaxableMixin
from trytond.modules.company.tests import (
CompanyTestMixin, PartyCompanyCheckEraseMixin, create_company, set_company)
from trytond.modules.currency.tests import create_currency
from trytond.modules.party.tests import PartyCheckReplaceMixin
from trytond.pool import Pool
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.transaction import Transaction, inactive_records
def create_chart(company, tax=False, chart='account.account_template_root_en'):
pool = Pool()
AccountTemplate = pool.get('account.account.template')
TaxTemplate = pool.get('account.tax.template')
TaxCodeTemplate = pool.get('account.tax.code.template')
ModelData = pool.get('ir.model.data')
CreateChart = pool.get('account.create_chart', type='wizard')
Account = pool.get('account.account')
module, xml_id = chart.split('.')
template = AccountTemplate(ModelData.get_id(module, xml_id))
if tax:
tax_account = AccountTemplate(ModelData.get_id(
'account', 'account_template_6_3_4_en'))
with Transaction().set_user(0):
tax = TaxTemplate()
tax.name = tax.description = '20% VAT'
tax.type = 'percentage'
tax.rate = Decimal('0.2')
tax.account = template
tax.invoice_account = tax_account
tax.credit_note_account = tax_account
tax.save()
TaxCodeTemplate.create([{
'name': 'Tax Code',
'account': template,
'lines': [('create', [{
'operator': '+',
'type': 'invoice',
'amount': 'tax',
'tax': tax.id,
}])],
}, {
'name': 'Base Code',
'account': template,
'lines': [('create', [{
'operator': '+',
'type': 'invoice',
'amount': 'base',
'tax': tax.id,
}])],
}])
session_id, _, _ = CreateChart.create()
create_chart = CreateChart(session_id)
create_chart.account.account_template = template
create_chart.account.company = company
create_chart.transition_create_account()
properties_state = create_chart.states['properties']
for name, value in properties_state.get_defaults(
create_chart, 'properties',
list(create_chart.properties._fields.keys())).items():
if name in create_chart.properties._fields:
setattr(create_chart.properties, name, value)
if not create_chart.properties.account_receivable:
receivable, = Account.search([
('type.receivable', '=', True),
('party_required', '=', True),
('company', '=', company.id),
], limit=1)
create_chart.properties.account_receivable = receivable
if not create_chart.properties.account_payable:
payable, = Account.search([
('type.payable', '=', True),
('party_required', '=', True),
('company', '=', company.id),
], limit=1)
create_chart.properties.account_payable = payable
create_chart.transition_create_properties()
def get_fiscalyear(company, today=None, start_date=None, end_date=None):
pool = Pool()
Sequence = pool.get('ir.sequence.strict')
SequenceType = pool.get('ir.sequence.type')
FiscalYear = pool.get('account.fiscalyear')
if not today:
today = datetime.date.today()
if not start_date:
start_date = today.replace(month=1, day=1)
if not end_date:
end_date = today.replace(month=12, day=31)
sequence_type, = SequenceType.search([
('name', '=', "Account Move"),
], limit=1)
sequence, = Sequence.create([{
'name': '%s' % today.year,
'sequence_type': sequence_type.id,
'company': company.id,
}])
fiscalyear = FiscalYear(name='%s' % today.year, company=company)
fiscalyear.start_date = start_date
fiscalyear.end_date = end_date
fiscalyear.move_sequence = sequence
return fiscalyear
def close_fiscalyear(fiscalyear):
pool = Pool()
Journal = pool.get('account.journal')
Period = pool.get('account.period')
Account = pool.get('account.account')
Move = pool.get('account.move')
FiscalYear = pool.get('account.fiscalyear')
BalanceNonDeferral = pool.get(
'account.fiscalyear.balance_non_deferral', type='wizard')
# Balance non-deferral
journal_closing, = Journal.create([{
'name': 'Closing',
'code': 'CLO',
'type': 'situation',
}])
period_closing, = Period.create([{
'name': 'Closing',
'start_date': fiscalyear.end_date,
'end_date': fiscalyear.end_date,
'fiscalyear': fiscalyear.id,
'type': 'adjustment',
}])
account_pl, = Account.search([
('code', '=', '3.2.1'),
])
session_id = BalanceNonDeferral.create()[0]
balance_non_deferral = BalanceNonDeferral(session_id)
balance_non_deferral.start.fiscalyear = fiscalyear
balance_non_deferral.start.journal = journal_closing
balance_non_deferral.start.period = period_closing
balance_non_deferral.start.credit_account = account_pl
balance_non_deferral.start.debit_account = account_pl
balance_non_deferral._execute('balance')
moves = Move.search([
('state', '=', 'draft'),
('period.fiscalyear', '=', fiscalyear.id),
])
Move.post(moves)
# Close fiscalyear
FiscalYear.close([fiscalyear])
class AccountTestCase(
PartyCompanyCheckEraseMixin, PartyCheckReplaceMixin, CompanyTestMixin,
ModuleTestCase):
'Test Account module'
module = 'account'
maxDiff = None
@with_transaction()
def test_account_chart(self):
'Test creation and update of minimal chart of accounts'
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
UpdateChart = pool.get('account.update_chart', type='wizard')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
root, = Account.search([('parent', '=', None)])
# Create an account and tax without template
cash, = Account.search([('code', '=', '1.1.1')])
Account.copy([cash.id])
tax, = Tax.search([])
Tax.copy([tax.id])
session_id, _, _ = UpdateChart.create()
update_chart = UpdateChart(session_id)
update_chart.start.account = root
update_chart.transition_update()
@with_transaction()
def test_account_chart_many_companies(self):
"Test creation of chart of accounts for many companies"
company1 = create_company()
with set_company(company1):
create_chart(company1, tax=True)
company2 = create_company()
with set_company(company2):
create_chart(company2, tax=True)
@with_transaction()
def test_fiscalyear(self):
'Test fiscalyear'
pool = Pool()
FiscalYear = pool.get('account.fiscalyear')
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
self.assertEqual(len(fiscalyear.periods), 12)
@with_transaction()
def test_fiscalyear_create_periods(self):
'Test fiscalyear create periods'
FiscalYear = Pool().get('account.fiscalyear')
company = create_company()
with set_company(company):
year = datetime.date.today().year
date = datetime.date
for start_date, end_date, interval, end_day, num_periods in [
(date(year, 1, 1), date(year, 12, 31), 1, 31, 12),
(date(year + 1, 1, 1), date(year + 1, 12, 31), 3, 31, 4),
(date(year + 2, 1, 1), date(year + 2, 12, 31), 5, 31, 3),
(date(year + 3, 4, 6), date(year + 4, 4, 5), 1, 5, 12),
(date(year + 4, 4, 6), date(year + 5, 4, 5), 3, 5, 4),
(date(year + 5, 4, 6), date(year + 6, 4, 5), 5, 5, 3),
(date(year + 6, 6, 6), date(year + 6, 12, 31), 1, 29, 8),
(date(year + 7, 7, 7), date(year + 7, 12, 31), 3, 29, 3),
(date(year + 8, 1, 1), date(year + 9, 8, 7), 1, 29, 20),
(date(year + 9, 9, 9), date(year + 10, 11, 12), 3, 29, 5),
]:
fiscalyear = get_fiscalyear(
company, start_date, start_date, end_date)
fiscalyear.save()
FiscalYear.create_period([fiscalyear], interval, end_day)
self.assertEqual(len(fiscalyear.periods), num_periods)
self.assertEqual(fiscalyear.periods[-1].end_date, end_date)
self.assertTrue(all(
p.end_date == p.end_date + relativedelta(day=end_day)
for p in fiscalyear.periods[:-1]))
self.assertEqual(fiscalyear.periods[0].start_date, start_date)
self.assertTrue(all(
p1.end_date + relativedelta(days=1) == p2.start_date
for p1, p2 in zip(
fiscalyear.periods[:-1], fiscalyear.periods[1:])))
@with_transaction()
def test_open_fiscalyear_before_open(self):
"Test create open fiscal year before an open one"
company = create_company()
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(
company,
start_date=datetime.date(2022, 1, 1),
end_date=datetime.date(2022, 12, 31))
fiscalyear.save()
earlier_fiscalyear = get_fiscalyear(
company,
start_date=datetime.date(2021, 1, 1),
end_date=datetime.date(2021, 12, 31))
earlier_fiscalyear.save()
@with_transaction()
def test_open_fiscalyear_before_close(self):
"Test create open fiscal year before a close one"
company = create_company()
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(
company,
start_date=datetime.date(2022, 1, 1),
end_date=datetime.date(2022, 12, 31))
fiscalyear.save()
close_fiscalyear(fiscalyear)
earlier_fiscalyear = get_fiscalyear(
company,
start_date=datetime.date(2021, 1, 1),
end_date=datetime.date(2021, 12, 31))
with self.assertRaises(SQLConstraintError):
earlier_fiscalyear.save()
@with_transaction()
def test_change_fiscalyear_dates_with_periods(self):
"Test change fiscal year dates"
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(
company,
start_date=datetime.date(2023, 1, 1),
end_date=datetime.date(2023, 12, 31))
fiscalyear.save()
fiscalyear.create_period([fiscalyear])
# Extend
fiscalyear.end_date = datetime.date(2024, 5, 31)
fiscalyear.save()
# Shorten
with self.assertRaises(PeriodDatesError):
fiscalyear.end_date = datetime.date(2023, 5, 31)
fiscalyear.save()
@with_transaction()
def test_change_period_dates_with_move(self):
"Test change period dates"
pool = Pool()
Period = pool.get('account.period')
Move = pool.get('account.move')
Journal = pool.get('account.journal')
company = create_company()
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
period = Period(
fiscalyear=fiscalyear,
type='adjustment',
name="Period",
start_date=fiscalyear.start_date,
end_date=fiscalyear.start_date)
period.save()
journal, = Journal.search([], limit=1)
move, = Move.create([{
'period': period.id,
'journal': journal.id,
'date': period.start_date,
}])
# Extend
period.end_date = fiscalyear.end_date
period.save()
# Shorten
with self.assertRaises(PeriodDatesError):
period.start_date = fiscalyear.end_date
period.save()
@with_transaction()
def test_account_debit_credit(self):
'Test account debit/credit'
pool = Pool()
Party = pool.get('party.party')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Account = pool.get('account.account')
Move = pool.get('account.move')
party = Party(name='Party')
party.save()
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
create_chart(company)
sec_cur = create_currency('sec')
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
journal_expense, = Journal.search([
('code', '=', 'EXP'),
])
revenue, = Account.search([
('type.revenue', '=', True),
('closed', '=', False),
], limit=1)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
expense, = Account.search([
('type.expense', '=', True),
('closed', '=', False),
], limit=1)
payable, = Account.search([
('type.payable', '=', True),
('closed', '=', False),
], limit=1)
cash, = Account.search([
('code', '=', '1.1.1'),
])
cash_cur, = Account.copy([cash], default={
'second_currency': sec_cur.id,
})
# Create some moves
vlist = [
{
'period': period.id,
'journal': journal_revenue.id,
'date': period.start_date,
'lines': [
('create', [{
'account': revenue.id,
'credit': Decimal(100),
}, {
'account': receivable.id,
'debit': Decimal(100),
'party': party.id,
}]),
],
},
{
'period': period.id,
'journal': journal_revenue.id,
'date': period.start_date,
'lines': [
('create', [{
'account': receivable.id,
'credit': Decimal(80),
'second_currency': sec_cur.id,
'amount_second_currency': -Decimal(50),
'party': party.id,
}, {
'account': cash_cur.id,
'debit': Decimal(80),
'second_currency': sec_cur.id,
'amount_second_currency': Decimal(50),
}]),
],
},
{
'period': period.id,
'journal': journal_expense.id,
'date': period.start_date,
'lines': [
('create', [{
'account': expense.id,
'debit': Decimal(30),
}, {
'account': payable.id,
'credit': Decimal(30),
'party': party.id,
}]),
],
},
]
Move.create(vlist)
# Test debit/credit
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(0), Decimal(100)))
self.assertEqual(revenue.balance, Decimal(-100))
self.assertEqual((cash_cur.debit, cash_cur.credit),
(Decimal(80), Decimal(0)))
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
# Use next fiscalyear
today = datetime.date.today()
next_fiscalyear = get_fiscalyear(company,
today=today + relativedelta(years=1))
next_fiscalyear.save()
FiscalYear.create_period([next_fiscalyear])
# Test debit/credit for next year
with Transaction().set_context(fiscalyear=next_fiscalyear.id):
revenue = Account(revenue.id)
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(0), Decimal(0)))
self.assertEqual(revenue.balance, Decimal(-100))
cash_cur = Account(cash_cur.id)
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
# Test debit/credit cumulate for next year
with Transaction().set_context(fiscalyear=next_fiscalyear.id,
cumulate=True):
revenue = Account(revenue.id)
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(0), Decimal(100)))
self.assertEqual(revenue.balance, Decimal(-100))
cash_cur = Account(cash_cur.id)
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
close_fiscalyear(fiscalyear)
# Check deferral
self.assertEqual(revenue.deferrals, ())
deferral_receivable, = receivable.deferrals
self.assertEqual(
(deferral_receivable.debit, deferral_receivable.credit),
(Decimal(100), Decimal(80)))
self.assertEqual(deferral_receivable.fiscalyear, fiscalyear)
cash_cur = Account(cash_cur.id)
deferral_cash_cur, = cash_cur.deferrals
self.assertEqual(
deferral_cash_cur.amount_second_currency, Decimal(50))
# Test debit/credit
with Transaction().set_context(fiscalyear=fiscalyear.id):
revenue = Account(revenue.id)
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(100), Decimal(100)))
self.assertEqual(revenue.balance, Decimal(0))
receivable = Account(receivable.id)
self.assertEqual((receivable.debit, receivable.credit),
(Decimal(100), Decimal(80)))
self.assertEqual(receivable.balance, Decimal(20))
cash_cur = Account(cash_cur.id)
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
# Test debit/credit for next year
with Transaction().set_context(fiscalyear=next_fiscalyear.id):
revenue = Account(revenue.id)
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(0), Decimal(0)))
self.assertEqual(revenue.balance, Decimal(0))
receivable = Account(receivable.id)
self.assertEqual((receivable.debit, receivable.credit),
(Decimal(0), Decimal(0)))
self.assertEqual(receivable.balance, Decimal(20))
cash_cur = Account(cash_cur.id)
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
# Test debit/credit cumulate for next year
with Transaction().set_context(fiscalyear=next_fiscalyear.id,
cumulate=True):
revenue = Account(revenue.id)
self.assertEqual((revenue.debit, revenue.credit),
(Decimal(0), Decimal(0)))
self.assertEqual(revenue.balance, Decimal(0))
receivable = Account(receivable.id)
self.assertEqual((receivable.debit, receivable.credit),
(Decimal(100), Decimal(80)))
self.assertEqual(receivable.balance, Decimal(20))
cash_cur = Account(cash_cur.id)
self.assertEqual(
cash_cur.amount_second_currency, Decimal(50))
@with_transaction()
def test_account_type_amount(self):
"Test account type amount"
pool = Pool()
Party = pool.get('party.party')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Account = pool.get('account.account')
Move = pool.get('account.move')
Type = pool.get('account.account.type')
party = Party(name='Party')
party.save()
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
create_chart(company)
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
revenue, = Account.search([
('type.revenue', '=', True),
('closed', '=', False),
], limit=1)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
Move.create([{
'period': period.id,
'journal': journal_revenue.id,
'date': period.start_date,
'lines': [
('create', [{
'account': revenue.id,
'credit': Decimal(100),
}, {
'account': receivable.id,
'debit': Decimal(100),
'party': party.id,
}]),
],
}])
with Transaction().set_context(fiscalyear=fiscalyear.id):
revenue_type = Type(revenue.type)
receivable_type = Type(receivable.type)
# Test type amount
self.assertEqual(revenue_type.amount, Decimal(100))
self.assertEqual(receivable_type.amount, Decimal(100))
# Set a debit type on receivable
with Transaction().set_context(fiscalyear=fiscalyear.id):
debit_receivable_type, = Type.copy([receivable_type])
receivable.debit_type = debit_receivable_type
receivable.credit_type = None
receivable.save()
self.assertEqual(receivable_type.amount, Decimal(0))
self.assertEqual(debit_receivable_type.amount, Decimal(100))
# Set a debit type on revenue
with Transaction().set_context(fiscalyear=fiscalyear.id):
debit_revenue_type, = Type.copy([revenue_type])
revenue.debit_type = debit_revenue_type
revenue.credit_type = None
revenue.save()
self.assertEqual(revenue_type.amount, Decimal(100))
self.assertEqual(debit_revenue_type.amount, Decimal(0))
# Set a credit type on revenue
with Transaction().set_context(fiscalyear=fiscalyear.id):
credit_revenue_type, = Type.copy([revenue_type])
revenue.credit_type = credit_revenue_type
revenue.debit_type = None
revenue.save()
self.assertEqual(revenue_type.amount, Decimal(0))
self.assertEqual(credit_revenue_type.amount, Decimal(100))
# Set a credit type on receivable
with Transaction().set_context(fiscalyear=fiscalyear.id):
credit_receivable_type, = Type.copy([receivable_type])
receivable.credit_type = credit_receivable_type
receivable.debit_type = None
receivable.save()
self.assertEqual(receivable_type.amount, Decimal(100))
self.assertEqual(credit_receivable_type.amount, Decimal(0))
@with_transaction()
def test_move_post(self):
"Test posting move"
pool = Pool()
Party = pool.get('party.party')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Account = pool.get('account.account')
Move = pool.get('account.move')
Line = pool.get('account.move.line')
Period = pool.get('account.period')
party = Party(name='Party')
party.save()
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
create_chart(company)
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
revenue, = Account.search([
('type.revenue', '=', True),
('closed', '=', False),
], limit=1)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.lines = [
Line(account=revenue, credit=Decimal(100)),
Line(account=receivable, debit=Decimal(100), party=party),
]
move.save()
Move.post([move])
move_id = move.id
self.assertEqual(move.state, 'posted')
# Move lines with debit = credit = 0 are automatically reconciled
receivable_no_party, = Account.copy([receivable], default={
'party_required': False,
})
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.lines = [
Line(account=receivable_no_party, credit=Decimal(0)),
Line(account=receivable, debit=Decimal(0), party=party),
]
move.save()
Move.post([move])
lines = Line.browse([l.id for l in move.lines
if l.account.reconcile])
self.assertTrue(all(bool(l.reconciliation) for l in lines))
# Can not post an empty move
with self.assertRaises(UserError):
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.save()
Move.post([move])
Move.delete([move])
# Can not modify posted move
with self.assertRaises(UserError):
move = Move(move_id)
move.date = period.end_date
move.save()
# Can not go back to draft
with self.assertRaises(UserError):
move = Move(move_id)
move.state = 'draft'
move.save()
Period.close([period])
# Can not create move with lines on closed period
with self.assertRaises(UserError):
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.lines = [
Line(account=revenue, credit=Decimal(100)),
Line(account=receivable, debit=Decimal(100), party=party),
]
move.save()
@with_transaction()
def test_find_best_reconciliation(self):
"Test find best reconciliation"
pool = Pool()
Account = pool.get('account.account')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Line = pool.get('account.move.line')
Move = pool.get('account.move')
Party = pool.get('party.party')
party = Party(name='Party')
party.save()
company = create_company()
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
currency = company.currency
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.save()
line1 = Line(
move=move, party=party,
debit=Decimal(10), credit=0,
account=receivable,
maturity_date=datetime.date(2024, 1, 1))
line2 = Line(
move=move, party=party,
debit=0, credit=Decimal(10),
account=receivable,
maturity_date=datetime.date(2024, 1, 2))
line3 = Line(
move=move, party=party,
debit=0, credit=Decimal(5),
account=receivable,
maturity_date=datetime.date(2024, 1, 3))
Line.save([line1, line2, line3])
for (lines, amount, best, remaining) in [
([line1], 0, [line1], Decimal('10')),
([line1], Decimal(10), [line1], Decimal(0)),
([line1], Decimal(3), [line1], Decimal(7)),
([line1, line2], 0, [line1, line2], Decimal(0)),
([line1, line2], Decimal(10), [line1], Decimal(0)),
([line1, line2], Decimal(-10), [line2], Decimal(0)),
([line1, line2], Decimal(20), [line1], Decimal(-10)),
([line1, line2], Decimal(-3), [line1, line2], Decimal(3)),
([line1, line2], Decimal(-9), [line2], Decimal(-1)),
([line1, line3], 0, [line1, line3], Decimal(5)),
([line1, line2, line3], 0, [line1, line2], Decimal(0)),
]:
with self.subTest(lines=lines, amount=amount):
self.assertEqual(
Line.find_best_reconciliation(lines, currency, amount),
(best, remaining))
@with_transaction()
def test_find_best_reconciliation_currency(self):
"Test find best reconciliation with different currencies"
pool = Pool()
Account = pool.get('account.account')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Line = pool.get('account.move.line')
Move = pool.get('account.move')
Party = pool.get('party.party')
currency1 = create_currency('USD')
currency2 = create_currency('EUR')
party = Party(name='Party')
party.save()
company = create_company(currency=currency1)
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.save()
line1 = Line(
move=move, party=party,
debit=Decimal(10), credit=0,
second_currency=currency2,
amount_second_currency=Decimal(10),
account=receivable,
maturity_date=datetime.date(2024, 1, 1))
line2 = Line(
move=move, party=party,
debit=0, credit=Decimal(20),
second_currency=currency2,
amount_second_currency=Decimal('-10'),
account=receivable, maturity_date=datetime.date(2024, 1, 1))
line3 = Line(
move=move, party=party,
debit=0, credit=Decimal(5),
second_currency=None, account=receivable,
maturity_date=datetime.date(2024, 1, 3))
Line.save([line1, line2, line3])
self.assertEqual(
Line.find_best_reconciliation(
[line1, line2, line3], currency2),
([line1, line2], Decimal(0)))
@with_transaction()
def test_tax_compute(self):
'Test tax compute/reverse_compute'
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
today = datetime.date.today()
company = create_company()
with set_company(company):
create_chart(company)
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax = Tax()
tax.name = tax.description = 'Test'
tax.type = 'none'
tax.invoice_account = tax_account
tax.credit_note_account = tax_account
child1 = Tax()
child1.name = child1.description = 'Child 1'
child1.type = 'percentage'
child1.rate = Decimal('0.2')
child1.invoice_account = tax_account
child1.credit_note_account = tax_account
child1.save()
child2 = Tax()
child2.name = child2.description = 'Child 1'
child2.type = 'fixed'
child2.amount = Decimal('10')
child2.invoice_account = tax_account
child2.credit_note_account = tax_account
child2.save()
tax.childs = [child1, child2]
tax.save()
self.assertEqual(Tax.compute([tax], Decimal('100'), 2, today),
[{
'base': Decimal('200'),
'amount': Decimal('40.0'),
'tax': child1,
}, {
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('130'), [tax], today),
Decimal('100'))
child1.end_date = today + relativedelta(days=5)
child1.save()
self.assertEqual(Tax.compute([tax], Decimal('100'), 2, today),
[{
'base': Decimal('200'),
'amount': Decimal('40.0'),
'tax': child1,
}, {
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('130'), [tax], today),
Decimal('100'))
child1.start_date = today + relativedelta(days=1)
child1.save()
self.assertEqual(Tax.compute([tax], Decimal('100'), 2, today),
[{
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('110'), [tax], today),
Decimal('100'))
self.assertEqual(Tax.compute([tax], Decimal('100'), 2,
today + relativedelta(days=1)), [{
'base': Decimal('200'),
'amount': Decimal('40.0'),
'tax': child1,
}, {
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal('130'), [tax], today + relativedelta(days=1)),
Decimal('100'))
self.assertEqual(Tax.compute([tax], Decimal('100'), 2,
today + relativedelta(days=5)), [{
'base': Decimal('200'),
'amount': Decimal('40.0'),
'tax': child1,
}, {
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('130'), [tax],
today + relativedelta(days=5)),
Decimal('100'))
self.assertEqual(Tax.compute([tax], Decimal('100'), 2,
today + relativedelta(days=6)), [{
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('110'), [tax],
today + relativedelta(days=6)),
Decimal('100'))
child1.end_date = None
child1.save()
self.assertEqual(Tax.compute([tax], Decimal('100'), 2,
today + relativedelta(days=6)), [{
'base': Decimal('200'),
'amount': Decimal('40.0'),
'tax': child1,
}, {
'base': Decimal('200'),
'amount': Decimal('20'),
'tax': child2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('130'), [tax],
today + relativedelta(days=6)),
Decimal('100'))
ecotax1 = Tax()
ecotax1.name = ecotax1.description = 'EcoTax 1'
ecotax1.type = 'fixed'
ecotax1.amount = Decimal(5)
ecotax1.invoice_account = tax_account
ecotax1.credit_note_account = tax_account
ecotax1.sequence = 10
ecotax1.save()
vat0 = Tax()
vat0.name = vat0.description = 'VAT0'
vat0.type = 'percentage'
vat0.rate = Decimal('0.1')
vat0.invoice_account = tax_account
vat0.credit_note_account = tax_account
vat0.sequence = 5
vat0.save()
vat1 = Tax()
vat1.name = vat1.description = 'VAT1'
vat1.type = 'percentage'
vat1.rate = Decimal('0.2')
vat1.invoice_account = tax_account
vat1.credit_note_account = tax_account
vat1.sequence = 20
vat1.save()
self.assertEqual(
Tax.compute([vat0, ecotax1, vat1], Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(10),
'tax': vat0,
}, {
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(100),
'amount': Decimal(20),
'tax': vat1,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal(135), [vat0, ecotax1, vat1], today),
Decimal(100))
@with_transaction()
def test_tax_compute_with_update_unit_price(self):
'Test tax compute with unit_price modifying tax'
pool = Pool()
Account = pool.get('account.account')
Date = pool.get('ir.date')
Tax = pool.get('account.tax')
today = Date.today()
company = create_company()
with set_company(company):
create_chart(company)
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
ecotax1 = Tax()
ecotax1.name = ecotax1.description = 'EcoTax 1'
ecotax1.type = 'fixed'
ecotax1.amount = Decimal(5)
ecotax1.invoice_account = tax_account
ecotax1.credit_note_account = tax_account
ecotax1.update_unit_price = True
ecotax1.sequence = 10
ecotax1.save()
vat1 = Tax()
vat1.name = vat1.description = 'VAT1'
vat1.type = 'percentage'
vat1.rate = Decimal('0.2')
vat1.invoice_account = tax_account
vat1.credit_note_account = tax_account
vat1.sequence = 20
vat1.save()
self.assertEqual(
Tax.compute([ecotax1, vat1], Decimal(100), 5, today),
[{
'base': Decimal(500),
'amount': Decimal(25),
'tax': ecotax1,
}, {
'base': Decimal(525),
'amount': Decimal(105),
'tax': vat1,
}])
self.assertEqual(
Tax.reverse_compute(Decimal(126), [ecotax1, vat1], today),
Decimal(100))
ecotax2 = Tax()
ecotax2.name = ecotax2.description = 'EcoTax 2'
ecotax2.type = 'percentage'
ecotax2.rate = Decimal('0.5')
ecotax2.invoice_account = tax_account
ecotax2.credit_note_account = tax_account
ecotax2.update_unit_price = True
ecotax2.sequence = 10
ecotax2.save()
self.assertEqual(
Tax.compute([ecotax1, ecotax2, vat1], Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(100),
'amount': Decimal(50),
'tax': ecotax2,
}, {
'base': Decimal(155),
'amount': Decimal(31),
'tax': vat1,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal(186), [ecotax1, ecotax2, vat1], today),
Decimal(100))
vat0 = Tax()
vat0.name = vat0.description = 'VAT0'
vat0.type = 'percentage'
vat0.rate = Decimal('0.1')
vat0.invoice_account = tax_account
vat0.credit_note_account = tax_account
vat0.sequence = 5
vat0.save()
self.assertEqual(
Tax.compute([vat0, ecotax1, vat1], Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(10),
'tax': vat0,
}, {
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(105),
'amount': Decimal(21),
'tax': vat1,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal(136), [vat0, ecotax1, vat1], today),
Decimal(100))
self.assertEqual(
Tax.compute([vat0, ecotax1, ecotax2, vat1],
Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(10),
'tax': vat0,
}, {
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(100),
'amount': Decimal(50),
'tax': ecotax2,
}, {
'base': Decimal(155),
'amount': Decimal(31),
'tax': vat1,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal(196), [vat0, ecotax1, ecotax2, vat1], today),
Decimal(100))
vat2 = Tax()
vat2.name = vat2.description = 'VAT2'
vat2.type = 'percentage'
vat2.rate = Decimal('0.3')
vat2.invoice_account = tax_account
vat2.credit_note_account = tax_account
vat2.sequence = 30
vat2.save()
self.assertEqual(
Tax.compute([vat0, ecotax1, vat1, vat2],
Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(10),
'tax': vat0,
}, {
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(105),
'amount': Decimal(21),
'tax': vat1,
}, {
'base': Decimal(105),
'amount': Decimal('31.5'),
'tax': vat2,
}])
self.assertEqual(
Tax.reverse_compute(
Decimal('167.5'), [vat0, ecotax1, vat1, vat2], today),
Decimal(100))
ecotax3 = Tax()
ecotax3.name = ecotax3.description = 'ECOTAX3'
ecotax3.type = 'percentage'
ecotax3.rate = Decimal('0.4')
ecotax3.invoice_account = tax_account
ecotax3.credit_note_account = tax_account
ecotax3.update_unit_price = True
ecotax3.sequence = 25
ecotax3.save()
self.assertEqual(
Tax.compute([vat0, ecotax1, vat1, ecotax3, vat2],
Decimal(100), 1, today),
[{
'base': Decimal(100),
'amount': Decimal(10),
'tax': vat0,
}, {
'base': Decimal(100),
'amount': Decimal(5),
'tax': ecotax1,
}, {
'base': Decimal(105),
'amount': Decimal(21),
'tax': vat1,
}, {
'base': Decimal(105),
'amount': Decimal('42'),
'tax': ecotax3,
}, {
'base': Decimal(147),
'amount': Decimal('44.1'),
'tax': vat2
}])
self.assertEqual(
Tax.reverse_compute(
Decimal('222.1'),
[vat0, ecotax1, vat1, ecotax3, vat2],
today),
Decimal(100))
class Taxable(TaxableMixin):
__slots__ = ('currency', 'taxable_lines', 'company')
def __init__(self, currency=None, taxable_lines=None, company=None):
super().__init__()
self.currency = currency
self.taxable_lines = taxable_lines
self.company = company
@with_transaction()
def test_taxable_mixin_line(self):
"Test TaxableMixin with rounding on line"
pool = Pool()
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
config = Configuration(1)
config.tax_rounding = 'line'
config.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax], Decimal('1.001'), 1, None),
] * 100,
company=company)
taxes = taxable._get_taxes().values()
tax, = taxes
self.assertEqual(tax.base, Decimal('100.00'))
self.assertEqual(tax.amount, Decimal('20.00'))
@with_transaction()
def test_taxable_mixin_line2(self):
"Test TaxableMixin with rounding on line"
pool = Pool()
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
tax.rate = 1
tax.save()
config = Configuration(1)
config.tax_rounding = 'line'
config.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax], Decimal('1.070'), 1, None),
([tax], Decimal('1.005'), 1, None),
],
company=company)
taxes = taxable._get_taxes().values()
tax, = taxes
self.assertEqual(tax.base, Decimal('2.07'))
self.assertEqual(tax.amount, Decimal('2.07'))
@with_transaction()
def test_taxable_mixin_document(self):
"Test TaxableMixin with rounding on document"
pool = Pool()
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
config = Configuration(1)
config.tax_rounding = 'document'
config.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax], Decimal('1.001'), 1, None),
] * 100,
company=company)
taxes = taxable._get_taxes().values()
tax, = taxes
self.assertEqual(tax.base, Decimal('100.00'))
self.assertEqual(tax.amount, Decimal('20.02'))
@with_transaction()
def test_taxable_mixin_many_taxable_lines(self):
"Test TaxableMixin with many taxable lines"
pool = Pool()
Tax = pool.get('account.tax')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax2, = Tax.search([])
tax1, = Tax.copy([tax2], default={'rate': Decimal('0.1')})
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax1], Decimal('10'), 1, None),
([tax1, tax2], Decimal('20'), 1, None),
],
company=company)
taxes = taxable._get_taxes().values()
self.assertEqual(len(taxes), 2)
tax_line1, = [t for t in taxes if t.tax == tax1]
tax_line2, = [t for t in taxes if t.tax == tax2]
self.assertEqual(tax_line1.base, Decimal('30.00'))
self.assertEqual(tax_line1.amount, Decimal('3.00'))
self.assertEqual(tax_line2.base, Decimal('20.00'))
self.assertEqual(tax_line2.amount, Decimal('4.00'))
@with_transaction()
def test_taxable_mixin_tax_residual_rounding(self):
"Test TaxableMixin for rounding with residual amount"
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company)
config = Configuration(1)
config.tax_rounding = 'line'
config.save()
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax1 = Tax()
tax1.name = tax1.description = "Tax 1"
tax1.type = 'percentage'
tax1.rate = Decimal('.1')
tax1.invoice_account = tax_account
tax1.credit_note_account = tax_account
tax1.save()
tax2 = Tax()
tax2.name = tax2.description = "Tax 2"
tax2.type = 'percentage'
tax2.rate = Decimal('.1')
tax2.invoice_account = tax_account
tax2.credit_note_account = tax_account
tax2.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax1, tax2], Decimal('1.0417'), 1, None),
],
company=company)
taxline_1, taxline_2 = taxable._get_taxes().values()
self.assertEqual(taxline_1.base, Decimal('1.04'))
self.assertEqual(taxline_1.amount, Decimal('.11'))
self.assertEqual(taxline_2.base, Decimal('1.04'))
self.assertEqual(taxline_2.amount, Decimal('.10'))
@with_transaction()
def test_taxable_mixin_tax_residual_rounding_with_0(self):
"Test TaxableMixin for rounding with residual amount and tax 0"
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company)
config = Configuration(1)
config.tax_rounding = 'line'
config.save()
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax0 = Tax()
tax0.name = tax0.description = "Tax 0"
tax0.type = 'percentage'
tax0.rate = Decimal('0')
tax0.invoice_account = tax_account
tax0.credit_note_account = tax_account
tax0.save()
tax1 = Tax()
tax1.name = tax1.description = "Tax 1"
tax1.type = 'percentage'
tax1.rate = Decimal('.1')
tax1.invoice_account = tax_account
tax1.credit_note_account = tax_account
tax1.save()
tax2 = Tax()
tax2.name = tax2.description = "Tax 2"
tax2.type = 'percentage'
tax2.rate = Decimal('.1')
tax2.invoice_account = tax_account
tax2.credit_note_account = tax_account
tax2.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax0, tax1, tax2], Decimal('1.0417'), 1, None),
],
company=company)
taxline_0, taxline_1, taxline_2 = taxable._get_taxes().values()
self.assertEqual(taxline_0.base, Decimal('1.04'))
self.assertEqual(taxline_0.amount, Decimal('0'))
self.assertEqual(taxline_1.base, Decimal('1.04'))
self.assertEqual(taxline_1.amount, Decimal('.11'))
self.assertEqual(taxline_2.base, Decimal('1.04'))
self.assertEqual(taxline_2.amount, Decimal('.10'))
@with_transaction()
def test_taxable_mixin_tax_residual_rounding_negative_residual(self):
"Test TaxableMixin for rounding with negative residual amount"
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company)
config = Configuration(1)
config.tax_rounding = 'line'
config.save()
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax1 = Tax()
tax1.name = tax1.description = "Tax 1"
tax1.type = 'percentage'
tax1.rate = Decimal('.1')
tax1.invoice_account = tax_account
tax1.credit_note_account = tax_account
tax1.save()
tax2 = Tax()
tax2.name = tax2.description = "Tax 2"
tax2.type = 'percentage'
tax2.rate = Decimal('.1')
tax2.invoice_account = tax_account
tax2.credit_note_account = tax_account
tax2.save()
# -2.95 is the unit price of -3.54 with 20% tax included
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax1], Decimal('30.00'), 1, None),
([tax1, tax2], Decimal('-2.95'), 1, None),
],
company=company)
taxline_1, taxline_2, taxline_3 = taxable._get_taxes().values()
self.assertEqual(taxline_1.base, Decimal('30.00'))
self.assertEqual(taxline_1.amount, Decimal('3.00'))
self.assertEqual(taxline_2.base, Decimal('-2.95'))
self.assertEqual(taxline_2.amount, Decimal('-0.29'))
self.assertEqual(taxline_3.base, Decimal('-2.95'))
self.assertEqual(taxline_3.amount, Decimal('-0.30'))
@with_transaction()
def test_taxable_mixin_tax_residual_rounding_per_same_taxes(self):
"""Test TaxableMixin for rounding with residual amount only for same
taxes"""
pool = Pool()
Account = pool.get('account.account')
Tax = pool.get('account.tax')
Configuration = pool.get('account.configuration')
currency = create_currency('cur')
company = create_company()
with set_company(company):
create_chart(company)
config = Configuration(1)
config.tax_rounding = 'document'
config.save()
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax = Tax()
tax.name = tax.description = "Tax"
tax.type = 'percentage'
tax.rate = Decimal('.06')
tax.invoice_account = tax_account
tax.credit_note_account = tax_account
tax.save()
taxable = self.Taxable(
currency=currency,
taxable_lines=[
([tax], Decimal('11.2736'), 1.04, None),
([tax], Decimal('0.4529'), -1, None),
],
company=company)
taxline_1, taxline_2 = taxable._get_taxes().values()
self.assertEqual(taxline_1.base, Decimal('11.72'))
self.assertEqual(taxline_1.amount, Decimal('0.7'))
self.assertEqual(taxline_2.base, Decimal('-0.45'))
self.assertEqual(taxline_2.amount, Decimal('-0.03'))
@with_transaction()
def test_tax_compute_with_children_update_unit_price(self):
"Test tax compute with children taxes modifying unit_price"
pool = Pool()
Account = pool.get('account.account')
Date = pool.get('ir.date')
Tax = pool.get('account.tax')
today = Date.today()
company = create_company()
with set_company(company):
create_chart(company)
tax_account, = Account.search([
('code', '=', '6.3.6'),
])
tax1 = Tax()
tax1.name = tax1.description = "Tax 1"
tax1.type = 'none'
tax1.update_unit_price = True
tax1.sequence = 1
tax1.save()
child1 = Tax()
child1.name = child1.description = "Child 1"
child1.type = 'percentage'
child1.rate = Decimal('0.1')
child1.invoice_account = tax_account
child1.credit_note_account = tax_account
child1.parent = tax1
child1.save()
tax2 = Tax()
tax2.name = tax2.description = "Tax 2"
tax2.type = 'fixed'
tax2.amount = Decimal('10')
tax2.invoice_account = tax_account
tax2.credit_note_account = tax_account
tax2.sequence = 2
tax2.save()
self.assertEqual(
Tax.compute([tax1, tax2], Decimal(100), 2, today), [{
'base': Decimal(200),
'amount': Decimal(20),
'tax': child1,
}, {
'base': Decimal('220'),
'amount': Decimal('20'),
'tax': tax2,
}])
self.assertEqual(
Tax.reverse_compute(Decimal('120'), [tax1, tax2], today),
Decimal('100'))
@with_transaction()
def test_receivable_payable(self):
'Test party receivable payable'
pool = Pool()
Company = pool.get('company.company')
Party = pool.get('party.party')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Account = pool.get('account.account')
Move = pool.get('account.move')
company = create_company()
with set_company(company):
create_chart(company)
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
journal_expense, = Journal.search([
('code', '=', 'EXP'),
])
revenue, = Account.search([
('type.revenue', '=', True),
('closed', '=', False),
], limit=1)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
expense, = Account.search([
('type.expense', '=', True),
('closed', '=', False),
], limit=1)
payable, = Account.search([
('type.payable', '=', True),
('closed', '=', False),
], limit=1)
party, = Party.create([{
'name': 'Receivable/Payable party',
}])
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
def get_move(journal, amount, credit_account, debit_account, party,
maturity_date=None):
return {
'period': period.id,
'journal': journal.id,
'date': period.start_date,
'lines': [
('create', [{
'account': credit_account.id,
'credit': amount,
}, {
'account': debit_account.id,
'debit': amount,
'party': party.id,
'maturity_date': maturity_date,
}]),
],
}
vlist = [
get_move(journal_revenue, Decimal(100), revenue, receivable,
party),
get_move(journal_expense, Decimal(30), expense, payable,
party),
get_move(journal_revenue, Decimal(200), revenue, receivable,
party, tomorrow),
get_move(journal_revenue, Decimal(60), expense, payable,
party, tomorrow),
]
moves = Move.create(vlist)
Move.post(moves)
def check_fields():
party_test = Party(party.id)
company_test = Company(company.id)
for record, Model in [
(party_test, Party),
(company_test, Company),
]:
for field, value in [
('receivable', Decimal('300')),
('receivable_today', Decimal('100')),
('payable', Decimal('90')),
('payable_today', Decimal('30')),
]:
with self.subTest(
record=record, field=field, value=value):
self.assertEqual(
getattr(record, field), value)
self.assertEqual(
Model.search([(field, '=', value)]),
[record])
self.assertEqual(
Model.search([(field, 'in', [value])]),
[record])
self.assertEqual(
Model.search([(field, '!=', value)]),
[])
self.assertEqual(
Model.search([(field, 'not in', [value])]),
[])
check_fields()
close_fiscalyear(fiscalyear)
check_fields()
@with_transaction()
def test_sort_taxes(self):
"Test sort_taxes"
pool = Pool()
Tax = pool.get('account.tax')
tax1 = Tax(sequence=None, id=-3)
tax2 = Tax(sequence=None, id=-2)
tax3 = Tax(sequence=1, id=-1)
self.assertSequenceEqual(
Tax.sort_taxes([tax3, tax2, tax1]), [tax1, tax2, tax3])
@with_transaction()
def test_configuration_accounts_on_party(self):
'Test configuration accounts are used as fallback on party'
pool = Pool()
Party = pool.get('party.party')
Account = pool.get('account.account')
party = Party(name='Party')
party.save()
self.assertIsNone(party.account_payable)
self.assertIsNone(party.account_receivable)
company = create_company()
with set_company(company):
create_chart(company)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
payable, = Account.search([
('type.payable', '=', True),
('closed', '=', False),
], limit=1)
party = Party(party.id)
self.assertEqual(party.account_payable_used, payable)
self.assertEqual(party.account_receivable_used, receivable)
@with_transaction()
def test_tax_rule(self):
"Test tax rule"
pool = Pool()
TaxRule = pool.get('account.tax.rule')
Tax = pool.get('account.tax')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
target_tax, = Tax.copy([tax])
tax_rule, = TaxRule.create([{
'name': 'Test',
'kind': 'both',
'lines': [('create', [{
'origin_tax': tax.id,
'tax': target_tax.id,
}])],
}])
self.assertListEqual(tax_rule.apply(tax, {}), [target_tax.id])
@with_transaction()
def test_tax_rule_start_date(self):
"Test tax rule start date"
pool = Pool()
TaxRule = pool.get('account.tax.rule')
Tax = pool.get('account.tax')
Date = pool.get('ir.date')
today = Date.today()
yesterday = today - datetime.timedelta(days=1)
tomorrow = today + datetime.timedelta(days=1)
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
target_tax, = Tax.copy([tax])
tax_rule, = TaxRule.create([{
'name': "Test",
'kind': 'both',
'lines': [('create', [{
'start_date': today,
'tax': target_tax.id,
}])],
}])
self.assertListEqual(tax_rule.apply(tax, {}), [target_tax.id])
self.assertListEqual(
tax_rule.apply(tax, {'date': yesterday}), [tax.id])
self.assertListEqual(
tax_rule.apply(tax, {'date': tomorrow}), [target_tax.id])
@with_transaction()
def test_tax_rule_end_date(self):
"Test tax rule end date"
pool = Pool()
TaxRule = pool.get('account.tax.rule')
Tax = pool.get('account.tax')
Date = pool.get('ir.date')
today = Date.today()
yesterday = today - datetime.timedelta(days=1)
tomorrow = today + datetime.timedelta(days=1)
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
target_tax, = Tax.copy([tax])
tax_rule, = TaxRule.create([{
'name': "Test",
'kind': 'both',
'lines': [('create', [{
'end_date': today,
'tax': target_tax.id,
}])],
}])
self.assertListEqual(tax_rule.apply(tax, {}), [target_tax.id])
self.assertListEqual(
tax_rule.apply(tax, {'date': yesterday}), [target_tax.id])
self.assertListEqual(
tax_rule.apply(tax, {'date': tomorrow}), [tax.id])
@with_transaction()
def test_tax_rule_keep_origin(self):
"Test tax rule keeps origin"
pool = Pool()
TaxRule = pool.get('account.tax.rule')
Tax = pool.get('account.tax')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
tax, = Tax.search([])
target_tax, = Tax.copy([tax])
tax_rule, = TaxRule.create([{
'name': 'Test',
'kind': 'both',
'lines': [('create', [{
'origin_tax': tax.id,
'tax': target_tax.id,
'keep_origin': True,
}])],
}])
self.assertListEqual(
tax_rule.apply(tax, {}), [target_tax.id, tax.id])
@with_transaction()
def test_update_chart(self):
'Test all template models are updated when updating chart'
pool = Pool()
TypeTemplate = pool.get('account.account.type.template')
AccountTemplate = pool.get('account.account.template')
TaxTemplate = pool.get('account.tax.template')
TaxCodeTemplate = pool.get('account.tax.code.template')
ModelData = pool.get('ir.model.data')
UpdateChart = pool.get('account.update_chart', type='wizard')
Type = pool.get('account.account.type')
Account = pool.get('account.account')
Tax = pool.get('account.tax')
TaxCode = pool.get('account.tax.code')
def check():
for type_ in Type.search([]):
self.assertEqual(type_.name, type_.template.name)
self.assertEqual(
type_.statement, type_.template.statement)
if type_.template.parent:
self.assertEqual(
type_.parent.name, type_.template.parent.name)
else:
self.assertEqual(type_.parent, None)
for account in Account.search([]):
self.assertEqual(account.name, account.template.name)
self.assertEqual(account.code, account.template.code)
self.assertEqual(
account.type.template if account.type else None,
account.template.type)
self.assertEqual(account.reconcile, account.template.reconcile)
self.assertEqual(
account.start_date, account.template.start_date)
self.assertEqual(account.end_date, account.template.end_date)
self.assertEqual(
account.party_required, account.template.party_required)
self.assertEqual(
account.general_ledger_balance,
account.template.general_ledger_balance)
self.assertEqual(
set(t.template for t in account.taxes),
set(t for t in account.template.taxes))
if account.template.parent:
self.assertEqual(
account.parent.name, account.template.parent.name)
else:
self.assertEqual(account.parent, None)
if account.template.replaced_by:
self.assertEqual(
account.replaced_by.name,
account.template.replaced_by.name)
else:
self.assertEqual(account.replaced_by, None)
for tax_code in TaxCode.search([]):
self.assertEqual(tax_code.name, tax_code.template.name)
self.assertEqual(tax_code.code, tax_code.template.code)
for line in tax_code.lines:
self.assertEqual(line.code.template, line.template.code)
self.assertEqual(line.operator, line.template.operator)
self.assertEqual(line.type, line.template.type)
self.assertEqual(line.tax.template, line.template.tax)
for tax in Tax.search([]):
self.assertEqual(tax.name, tax.template.name)
self.assertEqual(tax.description, tax.template.description)
self.assertEqual(tax.type, tax.template.type)
self.assertEqual(tax.rate, tax.template.rate)
self.assertEqual(tax.amount, tax.template.amount)
self.assertEqual(
tax.update_unit_price, tax.template.update_unit_price)
self.assertEqual(
tax.start_date, tax.template.start_date)
self.assertEqual(tax.end_date, tax.template.end_date)
self.assertEqual(
tax.invoice_account.template, tax.template.invoice_account)
self.assertEqual(
tax.credit_note_account.template,
tax.template.credit_note_account)
company = create_company()
with set_company(company):
create_chart(company, True)
with inactive_records():
self.assertEqual(Type.search([], count=True), 46)
self.assertEqual(Account.search([], count=True), 135)
self.assertEqual(Tax.search([], count=True), 1)
check()
with Transaction().set_user(0):
root_type = TypeTemplate(ModelData.get_id(
'account', 'account_type_template_root_en'))
root_type.name = "Updated " + root_type.name
root_type.save()
chart = AccountTemplate(ModelData.get_id(
'account', 'account_template_root_en'))
new_type = TypeTemplate()
new_type.name = 'New Type'
new_type.parent = root_type
new_type.statement = 'balance'
new_type.save()
updated_tax_type, = TypeTemplate.search([
('name', '=', "Liabilities and assets for current tax"),
])
updated_tax_type.parent = updated_tax_type.parent.parent
updated_tax_type.save()
new_account = AccountTemplate()
new_account.name = 'New Account'
new_account.parent = chart
new_account.type = new_type
new_account.save()
updated_tax, = TaxTemplate.search([])
updated_tax.name = 'VAT'
updated_tax.invoice_account = new_account
updated_tax.save()
# Can only change type which is compatible with previous parent
updated_account = AccountTemplate(ModelData.get_id(
'account', 'account_template_1_1_1_en'))
updated_account.code = 'REV'
updated_account.name = 'Updated Account'
updated_account.parent = new_account
updated_account.type = new_type
updated_account.reconcile = True
updated_account.end_date = datetime.date.today()
updated_account.taxes = [updated_tax]
updated_account.save()
inactive_account = AccountTemplate(ModelData.get_id(
'account', 'account_template_5_1_1_en'))
inactive_account.end_date = datetime.date.min
inactive_account.replaced_by = new_account
inactive_account.save()
new_tax = TaxTemplate()
new_tax.name = new_tax.description = '10% VAT'
new_tax.type = 'percentage'
new_tax.rate = Decimal('0.1')
new_tax.account = chart
new_tax.invoice_account = new_account
new_tax.credit_note_account = new_account
new_tax.save()
updated_tax_code, = TaxCodeTemplate.search([
('name', '=', 'Tax Code'),
])
updated_tax_code.name = 'Updated Tax Code'
updated_tax_code.save()
updated_tax_code_line, = updated_tax_code.lines
updated_tax_code_line.operator = '-'
updated_tax_code_line.save()
with set_company(company):
account, = Account.search([('parent', '=', None)])
session_id, _, _ = UpdateChart.create()
update_chart = UpdateChart(session_id)
update_chart.start.account = account
update_chart.transition_update()
with inactive_records():
self.assertEqual(Type.search([], count=True), 47)
self.assertEqual(Account.search([], count=True), 136)
self.assertEqual(Tax.search([], count=True), 2)
check()
@with_transaction()
def test_update_override(self):
"Test all models are not updated when template override is True"
pool = Pool()
ModelData = pool.get('ir.model.data')
TypeTemplate = pool.get('account.account.type.template')
AccountTemplate = pool.get('account.account.template')
TaxTemplate = pool.get('account.tax.template')
TaxCodeTemplate = pool.get('account.tax.code.template')
TaxCodeTemplateLine = pool.get('account.tax.code.line.template')
UpdateChart = pool.get('account.update_chart', type='wizard')
Type = pool.get('account.account.type')
Account = pool.get('account.account')
Tax = pool.get('account.tax')
TaxCode = pool.get('account.tax.code')
TaxCodeLine = pool.get('account.tax.code.line')
new_name = "Updated"
company = create_company()
with set_company(company):
create_chart(company, True)
type_count = Type.search([], count=True)
account_count = Account.search([], count=True)
tax_count = Tax.search([], count=True)
tax_code_count = TaxCode.search([], count=True)
tax_code_line_count = TaxCodeLine.search([], count=True)
with Transaction().set_user(0):
root = AccountTemplate(ModelData.get_id(
'account', 'account_template_root_en'))
template_type, = TypeTemplate.search([
('parent', '!=', None),
('parent', 'child_of', [root.type.id]),
], limit=1)
template_type.name = new_name
template_type.save()
type_, = Type.search([('template', '=', template_type.id)])
type_.template_override = True
type_.save()
template_account, = AccountTemplate.search([
('parent', '!=', None),
('parent', 'child_of', [root.id]),
], limit=1)
template_account.name = new_name
template_account.save()
account, = Account.search([('template', '=', template_account.id)])
account.template_override = True
account.save()
template_tax, = TaxTemplate.search([])
template_tax.name = new_name
template_tax.save()
tax, = Tax.search([('template', '=', template_tax.id)])
tax.template_override = True
tax.save()
template_tax_code, = TaxCodeTemplate.search([], limit=1)
template_tax_code.name = new_name
template_tax_code.save()
tax_code, = TaxCode.search(
[('template', '=', template_tax_code.id)])
tax_code.template_override = True
tax_code.save()
template_tax_code_line, = TaxCodeTemplateLine.search([], limit=1)
tax_code_line, = TaxCodeLine.search(
[('template', '=', template_tax_code_line.id)])
tax_code_line.template_override = True
tax_code_line.save()
with set_company(company):
account, = Account.search([('parent', '=', None)])
session_id, _, _ = UpdateChart.create()
update_chart = UpdateChart(session_id)
update_chart.start.account = account
update_chart.transition_update()
self.assertEqual(Type.search([], count=True), type_count)
self.assertEqual(Account.search([], count=True), account_count)
self.assertEqual(Tax.search([], count=True), tax_count)
self.assertEqual(
TaxCode.search([], count=True), tax_code_count)
self.assertEqual(
TaxCodeLine.search([], count=True), tax_code_line_count)
for Model in [Type, Account, Tax, TaxCode]:
for record in Model.search([]):
self.assertNotEqual(record.name, new_name)
@with_transaction()
def test_update_inactive(self):
"Test update chart of accounts with inactive account"
pool = Pool()
Account = pool.get('account.account')
UpdateChart = pool.get('account.update_chart', type='wizard')
company = create_company()
with set_company(company):
create_chart(company, tax=True)
root, = Account.search([('parent', '=', None)])
cash, = Account.search([('code', '=', '1.1.1')])
cash.template_override = True
cash.end_date = datetime.date.min
cash.save()
self.assertFalse(cash.active)
session_id, _, _ = UpdateChart.create()
update_chart = UpdateChart(session_id)
update_chart.start.account = root
update_chart.transition_update()
with inactive_records():
self.assertEqual(
Account.search([('code', '=', '1.1.1')], count=True),
1)
@with_transaction()
def test_update_chart_new_parent(self):
"Test update chart of accounts with new parent"
pool = Pool()
ModelData = pool.get('ir.model.data')
TypeTemplate = pool.get('account.account.type.template')
Type = pool.get('account.account.type')
AccountTemplate = pool.get('account.account.template')
Account = pool.get('account.account')
UpdateChart = pool.get('account.update_chart', type='wizard')
company = create_company()
with set_company(company):
create_chart(company, True)
with Transaction().set_user(0):
root_type_template = TypeTemplate(ModelData.get_id(
'account', 'account_type_template_root_en'))
type_template, = TypeTemplate.search([
('parent', '!=', None),
('parent', 'child_of', [root_type_template.id]),
], limit=1)
new_type_template, = TypeTemplate.copy([type_template])
type_template.parent = new_type_template
type_template.save()
root_template = AccountTemplate(ModelData.get_id(
'account', 'account_template_root_en'))
account_template, = AccountTemplate.search([
('parent', '!=', None),
('parent', 'child_of', [root_template.id]),
], limit=1)
new_account_template, = AccountTemplate.copy([account_template])
account_template.parent = new_account_template
account_template.save()
with set_company(company):
account, = Account.search([('parent', '=', None)])
session_id, _, _ = UpdateChart.create()
update_chart = UpdateChart(session_id)
update_chart.start.account = account
update_chart.transition_update()
new_type, = Type.search(
[('template', '=', new_type_template.id)])
type, = Type.search(
[('template', '=', type_template.id)])
self.assertEqual(type.parent, new_type)
new_account, = Account.search(
[('template', '=', new_account_template.id)])
account, = Account.search(
[('template', '=', account_template.id)])
self.assertEqual(account.parent, new_account)
del ModuleTestCase