trytond-analytic_line_state/tests/test_analytic_line_state.py

372 lines
15 KiB
Python

#!/usr/bin/env python
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
import datetime
import unittest
import sys
import os
from dateutil.relativedelta import relativedelta
from decimal import Decimal
DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
'..', '..', '..', '..', '..', 'trytond')))
if os.path.isdir(DIR):
sys.path.insert(0, os.path.dirname(DIR))
import trytond.tests.test_tryton
from trytond.exceptions import UserError
from trytond.tests.test_tryton import (POOL, DB_NAME, USER, CONTEXT,
test_view, test_depends)
from trytond.transaction import Transaction
class TestCase(unittest.TestCase):
'''
Test module.
'''
def setUp(self):
trytond.tests.test_tryton.install_module('analytic_line_state')
self.account = POOL.get('account.account')
self.analytic_account = POOL.get('analytic_account.account')
self.analytic_line = POOL.get('analytic_account.line')
self.company = POOL.get('company.company')
self.fiscalyear = POOL.get('account.fiscalyear')
self.journal = POOL.get('account.journal')
self.move = POOL.get('account.move')
self.sequence = POOL.get('ir.sequence')
def test0005views(self):
'''
Test views.
'''
test_view('analytic_line_state')
def test0006depends(self):
'''
Test depends.
'''
test_depends()
def test0010analytic_account_chart(self):
'Test creation of minimal analytic chart of accounts'
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
company, = self.company.search([('rec_name', '=', 'B2CK')])
currency = company.currency
revenue_expense = self.account.search([
('kind', 'in', ('revenue', 'expense')),
])
receivable_payable = self.account.search([
('kind', 'in', ('receivable', 'payable')),
])
other = self.account.search([
('kind', 'in', ('view', 'other')),
])
root, = self.analytic_account.create([{
'name': 'Root',
'company': company.id,
'currency': currency.id,
'type': 'root',
'analytic_required': [
('add', map(int, revenue_expense)),
],
'analytic_forbidden': [
('add', map(int, receivable_payable)),
],
'analytic_optional': [
('add', [a.id for a in other]),
],
},
])
self.analytic_account.create([{
'name': 'Projects',
'company': company.id,
'currency': currency.id,
'root': root.id,
'parent': root.id,
'type': 'view',
'childs': [
('create', [{
'name': 'Project 1',
'code': 'P1',
'company': company.id,
'currency': currency.id,
'root': root.id,
'type': 'normal',
}, {
'name': 'Project 2',
'code': 'P2',
'company': company.id,
'currency': currency.id,
'root': root.id,
'type': 'normal',
},
]),
],
},
])
# Check all General accounts are configured
self.assertEqual(len(root.analytic_pending_accounts), 0)
transaction.cursor.commit()
def test0020account_constraints(self):
'Test account configuration constraints'
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
company, = self.company.search([('rec_name', '=', 'B2CK')])
currency = company.currency
fiscalyear, = self.fiscalyear.search([])
period = fiscalyear.periods[0]
journal_revenue, = self.journal.search([
('code', '=', 'REV'),
])
journal_expense, = self.journal.search([
('code', '=', 'EXP'),
])
revenue, = self.account.search([
('kind', '=', 'revenue'),
])
receivable, = self.account.search([
('kind', '=', 'receivable'),
])
expense, = self.account.search([
('kind', '=', 'expense'),
])
payable, = self.account.search([
('kind', '=', 'payable'),
])
project1, = self.analytic_account.search([
('code', '=', 'P1'),
])
project2, = self.analytic_account.search([
('code', '=', 'P2'),
])
root = project1.root
# Can add account in required and forbidden
#with self.assertRaises(UserError):
# root.analytic_required = root.analytic_required + (receivable,)
# root.save()
## Can add account in required and optional
#with self.assertRaises(UserError):
# root.analytic_optional = root.analytic_optional + (expense,)
# root.save()
## Can add account in forbidden and optional
#with self.assertRaises(UserError):
# root.analytic_optional = root.analytic_optional + (receivable,)
# root.save()
# Can create move with analytic in analytic required account and
# without analytic in forbidden account
analytic_lines_value = [('create', [{
'name': 'Contribution',
'debit': Decimal(0),
'credit': Decimal(30000),
'currency': currency.id,
'account': project1.id,
'journal': journal_revenue.id,
}]),
]
valid_move_vals = {
'period': period.id,
'journal': journal_revenue.id,
'date': period.start_date,
'lines': [
('create', [{
'account': revenue.id,
'credit': Decimal(30000),
'analytic_lines': analytic_lines_value,
}, {
'account': receivable.id,
'debit': Decimal(30000),
}]),
],
}
valid_move, = self.move.create([valid_move_vals])
self.assertTrue(all(al.state == 'valid'
for ml in valid_move.lines for al in ml.analytic_lines))
# Can not post move without analytic in analytic required account
missing_analytic_vals = valid_move_vals.copy()
missing_analytic_vals['lines'] = [
('create', [{
'account': revenue.id,
'credit': Decimal(30000),
'analytic_lines': [],
}, {
'account': receivable.id,
'debit': Decimal(30000),
}]),
]
missing_analytic_move = self.move.create([missing_analytic_vals])
with self.assertRaises(UserError):
self.move.post(missing_analytic_move)
# Can not create move with analytic in analytic forbidden account
unexpected_analytic_vals = valid_move_vals.copy()
unexpected_analytic_vals['lines'] = [
('create', [
valid_move_vals['lines'][0][1][0], {
'account': receivable.id,
'debit': Decimal(30000),
'analytic_lines': analytic_lines_value,
}]),
]
with self.assertRaises(UserError):
self.move.create([unexpected_analytic_vals])
transaction.cursor.rollback()
def test0020analytic_line_state(self):
'Test of analytic line workflow'
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
company, = self.company.search([('rec_name', '=', 'B2CK')])
currency = company.currency
fiscalyear, = self.fiscalyear.search([])
period = fiscalyear.periods[0]
journal_revenue, = self.journal.search([
('code', '=', 'REV'),
])
journal_expense, = self.journal.search([
('code', '=', 'EXP'),
])
revenue, = self.account.search([
('kind', '=', 'revenue'),
])
receivable, = self.account.search([
('kind', '=', 'receivable'),
])
expense, = self.account.search([
('kind', '=', 'expense'),
])
payable, = self.account.search([
('kind', '=', 'payable'),
])
project1, = self.analytic_account.search([
('code', '=', 'P1'),
])
project2, = self.analytic_account.search([
('code', '=', 'P2'),
])
today = datetime.date.today()
# Create some moves
vlist = [{
'period': period.id,
'journal': journal_revenue.id,
'date': period.start_date,
'lines': [
('create', [{
'account': revenue.id,
'credit': Decimal(30000),
'analytic_lines': [
('create', [{
'name': 'Contribution',
'debit': Decimal(0),
'credit': Decimal(30000),
'currency': currency.id,
'account': project1.id,
'journal':
journal_revenue.id,
}]),
],
}, {
'account': receivable.id,
'debit': Decimal(30000),
}]),
],
}, {
'period': period.id,
'journal': journal_expense.id,
'date': period.start_date,
'lines': [
('create', [{
'account': expense.id,
'debit': Decimal(1100),
}, {
'account': payable.id,
'credit': Decimal(1100),
}]),
],
},
]
valid_move, draft_move = self.move.create(vlist)
# Check the Analytic lines of the valid move are in 'valid' state
self.assertTrue(all(al.state == 'valid'
for ml in valid_move.lines for al in ml.analytic_lines))
# Can post the move
self.move.post([valid_move])
self.assertEqual(valid_move.state, 'posted')
# Create some analytic lines on draft move and check how their
# state change
expense_move_line = [l for l in draft_move.lines
if l.account.kind == 'expense'][0]
line1, = self.analytic_line.create([{
'name': 'Materials purchase',
'debit': Decimal(600),
'currency': currency.id,
'account': project1.id,
'move_line': expense_move_line.id,
'journal': journal_expense.id,
'date': today - relativedelta(days=15),
}])
self.assertEqual(line1.state, 'draft')
## Can't post move because analytic is not valid
#with self.assertRaises(UserError):
# self.move.post([draft_move])
line2, = self.analytic_line.create([{
'name': 'Salaries',
'debit': Decimal(500),
'currency': currency.id,
'account': project1.id,
'journal': journal_expense.id,
'date': today - relativedelta(days=10),
}])
self.assertEqual(line1.state, 'draft')
line2.move_line = expense_move_line
line2.save()
self.assertEqual(line2.state, 'valid')
self.assertEqual(line1.state, 'valid')
# Can post the move
self.move.post([draft_move])
self.assertEqual(draft_move.state, 'posted')
transaction.cursor.rollback()
def suite():
suite = trytond.tests.test_tryton.suite()
from trytond.modules.company.tests import test_company
from trytond.modules.account.tests import test_account
exclude_tests = ('test0005views', 'test0006depends',
'test0020company_recursion', 'test0040user',
'test0020mon_grouping', 'test0040rate_unicity',
'test0060compute_nonfinite', 'test0070compute_nonfinite_worounding',
'test0080compute_same', 'test0090compute_zeroamount',
'test0100compute_zerorate', 'test0110compute_missingrate',
'test0120compute_bothmissingrate', 'test0130delete_cascade',
'scenario_account_reconciliation_rst')
for test in test_company.suite():
if test not in suite and test.id().split('.')[-1] not in exclude_tests:
print "Adding company test '%s'" % test.id().split('.')[-1]
suite.addTest(test)
for test in test_account.suite():
if test not in suite and test.id().split('.')[-1] not in exclude_tests:
print "Adding account test '%s'" % test.id().split('.')[-1]
suite.addTest(test)
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
return suite
if __name__ == '__main__':
unittest.TextTestRunner(verbosity=2).run(suite())