diff --git a/account.py b/account.py
index 6adee533ef..db6b6641e7 100644
--- a/account.py
+++ b/account.py
@@ -47,12 +47,6 @@ class TypeTemplate(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(TypeTemplate, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_types'),
- ]
- cls._error_messages.update({
- 'recursive_types': 'You can not create recursive types!',
- })
cls._order.insert(0, ('sequence', 'ASC'))
@classmethod
@@ -65,6 +59,11 @@ class TypeTemplate(ModelSQL, ModelView):
# Migration from 2.4: drop required on sequence
table.not_null_action('sequence', action='remove')
+ @classmethod
+ def validate(cls, records):
+ super(TypeTemplate, cls).validate(records)
+ cls.check_recursion(records, rec_name='name')
+
@staticmethod
def default_balance_sheet():
return False
@@ -187,12 +186,6 @@ class Type(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(Type, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_types'),
- ]
- cls._error_messages.update({
- 'recursive_types': 'You can not create recursive types!',
- })
cls._order.insert(0, ('sequence', 'ASC'))
@classmethod
@@ -205,6 +198,11 @@ class Type(ModelSQL, ModelView):
# Migration from 2.4: drop required on sequence
table.not_null_action('sequence', action='remove')
+ @classmethod
+ def validate(cls, types):
+ super(Type, cls).validate(types)
+ cls.check_recursion(types, rec_name='name')
+
@staticmethod
def default_balance_sheet():
return False
@@ -364,15 +362,14 @@ class AccountTemplate(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(AccountTemplate, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_accounts'),
- ]
- cls._error_messages.update({
- 'recursive_accounts': 'You can not create recursive accounts!',
- })
cls._order.insert(0, ('code', 'ASC'))
cls._order.insert(1, ('name', 'ASC'))
+ @classmethod
+ def validate(cls, templates):
+ super(AccountTemplate, cls).validate(templates)
+ cls.check_recursion(templates)
+
@staticmethod
def default_kind():
return 'view'
@@ -576,21 +573,22 @@ class Account(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(Account, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_accounts'),
- ]
cls._error_messages.update({
- 'recursive_accounts': 'You can not create recursive accounts!',
- 'delete_account_containing_move_lines': ('You can not delete '
- 'accounts containing move lines!'),
- })
+ 'delete_account_containing_move_lines': ('You can not delete '
+ 'account "%s" because it has move lines.'),
+ })
cls._sql_error_messages.update({
- 'parent_fkey': ('You can not delete accounts '
- 'that have children!'),
- })
+ 'parent_fkey': ('You can not delete accounts that have '
+ 'children.'),
+ })
cls._order.insert(0, ('code', 'ASC'))
cls._order.insert(1, ('name', 'ASC'))
+ @classmethod
+ def validate(cls, accounts):
+ super(Account, cls).validate(accounts)
+ cls.check_recursion(accounts)
+
@staticmethod
def default_left():
return 0
@@ -870,10 +868,12 @@ class Account(ModelSQL, ModelView):
childs = cls.search([
('parent', 'child_of', [a.id for a in accounts]),
])
- if MoveLine.search([
- ('account', 'in', [a.id for a in childs]),
- ]):
- cls.raise_user_error('delete_account_containing_move_lines')
+ lines = MoveLine.search([
+ ('account', 'in', [a.id for a in childs]),
+ ])
+ if lines:
+ cls.raise_user_error('delete_account_containing_move_lines', (
+ lines[0].account.rec_name,))
super(Account, cls).delete(accounts)
def update_account(self, template2account=None, template2type=None):
@@ -2061,7 +2061,8 @@ class OpenAgedBalance(Wizard):
super(OpenAgedBalance, cls).__setup__()
cls._error_messages.update({
'warning': 'Warning',
- 'term_overlap_desc': 'You cannot define overlapping terms'})
+ 'term_overlap_desc': 'You cannot define overlapping terms',
+ })
def do_print_(self, action):
if not (self.start.term1 < self.start.term2 < self.start.term3):
diff --git a/account.xml b/account.xml
index 28f550082b..f549d98cdb 100644
--- a/account.xml
+++ b/account.xml
@@ -703,5 +703,41 @@ this repository contains the full copyright notices and license terms. -->
id="menu_aged_balance" icon="tryton-print"
name="Aged Balance"/>
+
+ account.account.type.template
+ en_US
+ error
+ recursion_error
+ Recursion error: Account Type Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+
+
+ account.account.type
+ en_US
+ error
+ recursion_error
+ Recursion error: Account Type "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+
+
+ account.account.template
+ en_US
+ error
+ recursion_error
+ Recursion error: Account Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+
+
+ account.account
+ en_US
+ error
+ recursion_error
+ Recursion error: Account "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+
diff --git a/fiscalyear.py b/fiscalyear.py
index 793ece34eb..1fb72e2220 100644
--- a/fiscalyear.py
+++ b/fiscalyear.py
@@ -51,26 +51,22 @@ class FiscalYear(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(FiscalYear, cls).__setup__()
- cls._constraints += [
- ('check_dates', 'fiscalyear_overlaps'),
- ('check_post_move_sequence', 'different_post_move_sequence'),
- ]
cls._order.insert(0, ('start_date', 'ASC'))
cls._error_messages.update({
- 'change_post_move_sequence': ('You can not change '
- 'the post move sequence'),
- 'no_fiscalyear_date': 'No fiscal year defined for this date!',
- 'fiscalyear_overlaps':
- 'You can not have 2 fiscal years that overlaps!',
- 'different_post_move_sequence':
- 'You must have different post move sequence per fiscal year!',
- 'account_balance_not_zero':
- 'The balance of the account "%s" must be zero!',
- 'close_error': ('You can not close a fiscal year until '
- 'there is older fiscal year opened!'),
- 'reopen_error': ('You can not reopen a fiscal year until '
- 'there is more recent fiscal year closed!'),
- })
+ 'change_post_move_sequence': ('You can not change the post '
+ 'move sequence in fiscal year "%s".'),
+ 'no_fiscalyear_date': 'No fiscal year defined for "%s".',
+ 'fiscalyear_overlaps': ('Fiscal year "%(first)s" and '
+ '"%(second)s" overlap.'),
+ 'different_post_move_sequence': ('Fiscal year "%(first)s" and '
+ '"%(second)s" have the same post move sequence.'),
+ 'account_balance_not_zero': ('The balance of the account "%s" '
+ 'must be zero.'),
+ 'close_error': ('You can not close fiscal year "%s" until you '
+ 'close all previous fiscal years.'),
+ 'reopen_error': ('You can not reopen fiscal year "%s" until '
+ 'you reopen all later fiscal years.'),
+ })
cls._buttons.update({
'create_period': {
'invisible': ((Eval('state') != 'open')
@@ -96,6 +92,13 @@ class FiscalYear(ModelSQL, ModelView):
def default_company():
return Transaction().context.get('company')
+ @classmethod
+ def validate(cls, years):
+ super(FiscalYear, cls).validate(years)
+ for year in years:
+ year.check_dates()
+ year.check_post_move_sequence()
+
def check_dates(self):
cursor = Transaction().cursor
cursor.execute('SELECT id '
@@ -109,17 +112,24 @@ class FiscalYear(ModelSQL, ModelView):
self.end_date, self.end_date,
self.start_date, self.end_date,
self.company.id, self.id))
- if cursor.fetchone():
- return False
- return True
+ second_id = cursor.fetchone()
+ if second_id:
+ second = self.__class__(second_id[0])
+ self.raise_user_error('fiscalyear_overlaps', {
+ 'first': self.rec_name,
+ 'second': second.rec_name,
+ })
def check_post_move_sequence(self):
- if self.search([
- ('post_move_sequence', '=', self.post_move_sequence.id),
- ('id', '!=', self.id),
- ]):
- return False
- return True
+ years = self.search([
+ ('post_move_sequence', '=', self.post_move_sequence.id),
+ ('id', '!=', self.id),
+ ])
+ if years:
+ self.raise_user_error('different_post_move_sequence', {
+ 'first': self.rec_name,
+ 'second': years[0].rec_name,
+ })
@classmethod
def write(cls, fiscalyears, vals):
@@ -128,7 +138,8 @@ class FiscalYear(ModelSQL, ModelView):
if fiscalyear.post_move_sequence and \
fiscalyear.post_move_sequence.id != \
vals['post_move_sequence']:
- cls.raise_user_error('change_post_move_sequence')
+ cls.raise_user_error('change_post_move_sequence', (
+ fiscalyear.rec_name,))
vals = vals.copy()
if 'periods' in vals:
operator = ['delete', 'unlink_all', 'unlink', 'create', 'write',
@@ -189,7 +200,9 @@ class FiscalYear(ModelSQL, ModelView):
If exception is set the function will raise an exception
if any fiscal year is found.
'''
- Date = Pool().get('ir.date')
+ pool = Pool()
+ Lang = pool.get('ir.lang')
+ Date = pool.get('ir.date')
if not date:
date = Date.today()
@@ -200,7 +213,13 @@ class FiscalYear(ModelSQL, ModelView):
], order=[('start_date', 'DESC')], limit=1)
if not fiscalyears:
if exception:
- cls.raise_user_error('no_fiscalyear_date')
+ language = Transaction().language
+ languages = Lang.search([('code', '=', language)])
+ if not languages:
+ languages = Lang.search([('code', '=', 'en_US')])
+ language, = languages
+ formatted = Lang.strftime(date, language.code, language.date)
+ cls.raise_user_error('no_fiscalyear_date', (formatted,))
else:
return None
return fiscalyears[0].id
@@ -242,7 +261,7 @@ class FiscalYear(ModelSQL, ModelView):
('state', '=', 'open'),
('company', '=', fiscalyear.company.id),
]):
- cls.raise_user_error('close_error')
+ cls.raise_user_error('close_error', (fiscalyear.rec_name,))
#First close the fiscalyear to be sure
#it will not have new period created between.
diff --git a/journal.py b/journal.py
index 794a081d8e..b94fe0b38f 100644
--- a/journal.py
+++ b/journal.py
@@ -31,7 +31,7 @@ class JournalType(ModelSQL, ModelView):
def __setup__(cls):
super(JournalType, cls).__setup__()
cls._sql_constraints += [
- ('code_uniq', 'UNIQUE(code)', 'The code must be unique!'),
+ ('code_uniq', 'UNIQUE(code)', 'The code must be unique.'),
]
cls._order.insert(0, ('code', 'ASC'))
@@ -199,17 +199,18 @@ class JournalPeriod(ModelSQL, ModelView):
super(JournalPeriod, cls).__setup__()
cls._sql_constraints += [
('journal_period_uniq', 'UNIQUE(journal, period)',
- 'You can only open one journal per period!'),
+ 'You can only open one journal per period.'),
]
cls._order.insert(0, ('name', 'ASC'))
cls._error_messages.update({
- 'modify_del_journal_period': ('You can not modify/delete '
- 'a journal - period with moves!'),
- 'create_journal_period': ('You can not create '
- 'a journal - period on a closed period!'),
- 'open_journal_period': ('You can not open '
- 'a journal - period from a closed period!'),
- })
+ 'modify_del_journal_period': ('You can not modify/delete '
+ 'journal - period "%s" because it has moves.'),
+ 'create_journal_period': ('You can not create a '
+ 'journal - period on closed period "%s".'),
+ 'open_journal_period': ('You can not open '
+ 'journal - period "%(journal_period)s" because period '
+ '"%(period)s" is closed.'),
+ })
@staticmethod
def default_active():
@@ -231,7 +232,8 @@ class JournalPeriod(ModelSQL, ModelView):
('period', '=', period.period.id),
], limit=1)
if moves:
- cls.raise_user_error('modify_del_journal_period')
+ cls.raise_user_error('modify_del_journal_period', (
+ period.rec_name,))
@classmethod
def create(cls, vlist):
@@ -240,7 +242,8 @@ class JournalPeriod(ModelSQL, ModelView):
if vals.get('period'):
period = Period(vals['period'])
if period.state == 'close':
- cls.raise_user_error('create_journal_period')
+ cls.raise_user_error('create_journal_period', (
+ period.rec_name,))
return super(JournalPeriod, cls).create(vlist)
@classmethod
@@ -251,7 +254,10 @@ class JournalPeriod(ModelSQL, ModelView):
if vals.get('state') == 'open':
for journal_period in periods:
if journal_period.period.state == 'close':
- cls.raise_user_error('open_journal_period')
+ cls.raise_user_error('open_journal_period', {
+ 'journal_period': journal_period.rec_name,
+ 'period': journal_period.period.rec_name,
+ })
super(JournalPeriod, cls).write(periods, vals)
@classmethod
diff --git a/move.py b/move.py
index de818987f7..df91350356 100644
--- a/move.py
+++ b/move.py
@@ -68,31 +68,28 @@ class Move(ModelSQL, ModelView):
def __setup__(cls):
super(Move, cls).__setup__()
cls._check_modify_exclude = ['state']
- cls._constraints += [
- ('check_centralisation', 'period_centralized_journal'),
- ('check_company', 'company_in_move'),
- ('check_date', 'date_outside_period'),
- ]
cls._order.insert(0, ('date', 'DESC'))
cls._order.insert(1, ('number', 'DESC'))
cls._error_messages.update({
- 'del_posted_move': 'You can not delete posted moves!',
- 'post_empty_move': 'You can not post an empty move!',
- 'post_unbalanced_move': 'You can not post an unbalanced move!',
- 'draft_posted_move_journal': ('You can not set a posted move '
- 'to draft in this journal!'),
- 'modify_posted_move': 'Move "%s" is already posted!\n'
- 'You can not modify a posted move.',
- 'period_centralized_journal': ('You can not create more than '
- 'one move per period\n'
- 'in a centralized journal!'),
- 'company_in_move': ('You can not create lines on accounts\n'
- 'of different companies in the same move!'),
- 'date_outside_period': ('You can not create move '
- 'with a date outside the period!'),
- 'draft_closed_period': ('You can not set to draft a move '
- 'from a closed period'),
- })
+ 'post_empty_move': ('You can not post move "%s" because it is '
+ 'empty.'),
+ 'post_unbalanced_move': ('You can not post move "%s" because '
+ 'it is an unbalanced.'),
+ 'draft_posted_move_journal': ('You can not set posted move '
+ '"%(move)s" to draft in journal "%(journal)s".'),
+ 'modify_posted_move': ('You can not modify move "%s" because '
+ 'it is already posted.'),
+ 'period_centralized_journal': ('Move "%(move)s" cannot be '
+ 'created because there is already a move in journal '
+ '"%(journal)s" and you cannot create more than one move '
+ 'per period in a centralized journal.'),
+ 'company_in_move': ('You can not create lines on accounts'
+ 'of different companies in move "%s".'),
+ 'date_outside_period': ('You can not create move "%(move)s" '
+ 'because it\'s date is outside its period.'),
+ 'draft_closed_period': ('You can not set to draft move '
+ '"%(move)s" because period "%(period)s" is closed.'),
+ })
cls._buttons.update({
'post': {
'invisible': Eval('state') == 'posted',
@@ -171,6 +168,14 @@ class Move(ModelSQL, ModelView):
])
return [('', '')] + [(m.model, m.name) for m in models]
+ @classmethod
+ def validate(cls, moves):
+ super(Move, cls).validate(moves)
+ for move in moves:
+ move.check_centralisation()
+ move.check_company()
+ move.check_date()
+
def check_centralisation(self):
if self.journal.centralised:
moves = self.search([
@@ -179,8 +184,10 @@ class Move(ModelSQL, ModelView):
('state', '!=', 'posted'),
], limit=2)
if len(moves) > 1:
- return False
- return True
+ self.raise_user_error('period_centralized_journal', {
+ 'move': self.rec_name,
+ 'journal': self.journal.rec_name,
+ })
def check_company(self):
company_id = -1
@@ -188,19 +195,19 @@ class Move(ModelSQL, ModelView):
if company_id < 0:
company_id = line.account.company.id
if line.account.company.id != company_id:
- return False
- return True
+ self.raise_user_error('company_in_move', (self.rec_name,))
def check_date(self):
- return self.period.start_date <= self.date <= self.period.end_date
+ if (self.date < self.period.start_date
+ or self.date > self.period.end_date):
+ self.raise_user_error('date_outside_period', (self.rec_name,))
@classmethod
def check_modify(cls, moves):
'Check posted moves for modifications.'
for move in moves:
if move.state == 'posted':
- cls.raise_user_error('modify_posted_move',
- error_args=(move.name,))
+ cls.raise_user_error('modify_posted_move', (move.name,))
@classmethod
def search_rec_name(cls, name, clause):
@@ -219,7 +226,7 @@ class Move(ModelSQL, ModelView):
if len(keys):
cls.check_modify(moves)
super(Move, cls).write(moves, vals)
- cls.validate(moves)
+ cls.validate_move(moves)
@classmethod
def create(cls, vlist):
@@ -247,7 +254,7 @@ class Move(ModelSQL, ModelView):
cls.write([move], {
'centralised_line': line.id,
})
- cls.validate(moves)
+ cls.validate_move(moves)
return moves
@classmethod
@@ -280,7 +287,7 @@ class Move(ModelSQL, ModelView):
return new_moves
@classmethod
- def validate(cls, moves):
+ def validate_move(cls, moves):
'''
Validate balanced move and centralise it if in centralised journal
'''
@@ -388,14 +395,14 @@ class Move(ModelSQL, ModelView):
for move in moves:
amount = Decimal('0.0')
if not move.lines:
- cls.raise_user_error('post_empty_move')
+ cls.raise_user_error('post_empty_move', (move.rec_name,))
company = None
for line in move.lines:
amount += line.debit - line.credit
if not company:
company = line.account.company
if not company.currency.is_zero(amount):
- cls.raise_user_error('post_unbalanced_move')
+ cls.raise_user_error('post_unbalanced_move', (move.rec_name,))
for move in moves:
values = {
'state': 'posted',
@@ -411,10 +418,16 @@ class Move(ModelSQL, ModelView):
def draft(cls, moves):
for move in moves:
if not move.journal.update_posted:
- cls.raise_user_error('draft_posted_move_journal')
+ cls.raise_user_error('draft_posted_move_journal', {
+ 'move': move.rec_name,
+ 'journal': move.journal.rec_name,
+ })
if move.period.state == 'close':
- cls.raise_user_error('draft_closed_period')
- return cls.write(moves, {
+ cls.raise_user_error('draft_closed_period', {
+ 'move': move.rec_name,
+ 'journal': move.period.rec_name,
+ })
+ cls.write(moves, {
'state': 'draft',
})
@@ -429,16 +442,23 @@ class Reconciliation(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(Reconciliation, cls).__setup__()
- cls._constraints += [
- ('check_lines', 'invalid_reconciliation'),
- ]
cls._error_messages.update({
- 'modify': 'You can not modify a reconciliation!',
- 'invalid_reconciliation': ('You can not create reconciliation '
- 'where lines are not balanced, nor valid, '
- 'nor in the same account, nor in account to reconcile, '
- 'nor from the same party!'),
- })
+ 'modify': 'You can not modify a reconciliation.',
+ 'reconciliation_line_not_valid': ('You can not reconcile line '
+ '"%s" because it is not in valid state.'),
+ 'reconciliation_different_accounts': ('You can not reconcile '
+ 'line "%(line)s" because it\'s account "%(account1)s" is '
+ 'different from "%(account2)s".'),
+ 'reconciliation_account_no_reconcile': ('You can not reconcile '
+ 'line "%(line)s" because it\'s account "%(account)s" is '
+ 'configured as not reconcilable.'),
+ 'reconciliation_different_parties': ('You can not reconcile '
+ 'line "%(line)s" because it\'s party "%(party1)s" is '
+ 'different from %(party2)s".'),
+ 'reconciliation_unbalanced': ('You can not create a '
+ 'reconciliation where debit "%(debit)s" and credit '
+ '"%(credit)s" differ.'),
+ })
@classmethod
def create(cls, vlist):
@@ -455,29 +475,59 @@ class Reconciliation(ModelSQL, ModelView):
def write(cls, moves, vals):
cls.raise_user_error('modify')
+ @classmethod
+ def validate(cls, reconciliations):
+ super(Reconciliation, cls).validate(reconciliations)
+ cls.check_lines(reconciliations)
+
@classmethod
def check_lines(cls, reconciliations):
for reconciliation in reconciliations:
amount = Decimal('0.0')
+ debit = Decimal('0.0')
+ credit = Decimal('0.0')
account = None
party = None
for line in reconciliation.lines:
if line.state != 'valid':
- return False
- amount += line.debit - line.credit
+ cls.raise_user_error('reconciliation_line_not_valid',
+ (line.rec_name,))
+ debit += line.debit
+ credit += line.credit
if not account:
account = line.account
elif account.id != line.account.id:
- return False
+ cls.raise_user_error('reconciliation_different_accounts', {
+ 'line': line.rec_name,
+ 'account1': line.account.rec_name,
+ 'account2': account.rec_name,
+ })
if not account.reconcile:
- return False
+ cls.raise_user_error('reconciliation_account_no_reconcile',
+ {
+ 'line': line.rec_name,
+ 'account': line.account.rec_name,
+ })
if not party:
party = line.party
elif line.party and party.id != line.party.id:
- return False
- if not account.company.currency.is_zero(amount):
- return False
- return True
+ cls.raise_user_error('reconciliation_different_parties', {
+ 'line': line.rec_name,
+ 'party1': line.party.rec_name,
+ 'party2': party.rec_name,
+ })
+ if not account.company.currency.is_zero(debit - credit):
+ language = Transaction().language
+ languages = Lang.search([('code', '=', language)])
+ if not languages:
+ languages = Lang.search([('code', '=', 'en_US')])
+ language = languages[0]
+ debit = Lang.currency(lang, debit, account.company.currency)
+ credit = Lang.currency(lang, credit, account.company.currency)
+ cls.raise_user_error('reconciliation_unbalanced', {
+ 'debit': debit,
+ 'credit': credit,
+ })
class Line(ModelSQL, ModelView):
@@ -553,10 +603,7 @@ class Line(ModelSQL, ModelView):
cls._sql_constraints += [
('credit_debit',
'CHECK(credit * debit = 0.0)',
- 'Wrong credit/debit values!'),
- ]
- cls._constraints += [
- ('check_account', 'move_view_inactive_account'),
+ 'Wrong credit/debit values.'),
]
cls.__rpc__.update({
'on_write': RPC(instantiate=0),
@@ -564,15 +611,20 @@ class Line(ModelSQL, ModelView):
})
cls._order[0] = ('id', 'DESC')
cls._error_messages.update({
- 'add_modify_closed_journal_period': ('You can not '
- 'add/modify lines in a closed journal period!'),
- 'modify_posted_move': 'You can not modify lines of a posted move!',
- 'modify_reconciled': 'You can not modify reconciled lines!',
- 'no_journal': 'No journal defined!',
- 'move_view_inactive_account': ('You can not create move lines\n'
- 'on view/inactive accounts!'),
- 'already_reconciled': 'Line "%s" (%d) already reconciled!',
- })
+ 'add_modify_closed_journal_period': ('You can not '
+ 'add/modify lines in closed journal period "%s".'),
+ 'modify_posted_move': ('You can not modify lines of move "%s" '
+ 'because it is already posted.'),
+ 'modify_reconciled': ('You can not modify line "%s" because it '
+ 'is reconciled.'),
+ 'no_journal': ('Move line cannot be created because there is '
+ 'no journal defined.'),
+ 'move_view_account': ('You can not create a move line with '
+ 'account "%s" because it is a view account.'),
+ 'move_inactive_account': ('You can not create a move line with '
+ 'account "%s" because it is inactive.'),
+ 'already_reconciled': 'Line "%s" (%d) already reconciled.',
+ })
@classmethod
def __register__(cls, module_name):
@@ -1136,12 +1188,19 @@ class Line(ModelSQL, ModelView):
def on_write(cls, lines):
return list(set(l.id for line in lines for l in line.move.lines))
+ @classmethod
+ def validate(cls, lines):
+ super(Line, cls).validate(lines)
+ for line in lines:
+ line.check_account()
+
def check_account(self):
if self.account.kind in ('view',):
- return False
+ self.raise_user_error('move_view_account', (
+ self.account.rec_name,))
if not self.account.active:
- return False
- return True
+ self.raise_user_error('move_inactive_account', (
+ self.account.rec_name,))
@classmethod
def check_journal_period_modify(cls, period, journal):
@@ -1157,7 +1216,8 @@ class Line(ModelSQL, ModelView):
if journal_periods:
journal_period, = journal_periods
if journal_period.state == 'close':
- cls.raise_user_error('add_modify_closed_journal_period')
+ cls.raise_user_error('add_modify_closed_journal_period', (
+ journal_period.rec_name,))
else:
JournalPeriod.create([{
'name': journal.name + ' - ' + period.name,
@@ -1173,9 +1233,11 @@ class Line(ModelSQL, ModelView):
journal_period_done = []
for line in lines:
if line.move.state == 'posted':
- cls.raise_user_error('modify_posted_move')
+ cls.raise_user_error('modify_posted_move', (
+ line.move.rec_name,))
if line.reconciliation:
- cls.raise_user_error('modify_reconciled')
+ cls.raise_user_error('modify_reconciled', (
+ line.rec_name,))
journal_period = (line.journal.id, line.period.id)
if journal_period not in journal_period_done:
cls.check_journal_period_modify(line.period,
@@ -1188,7 +1250,7 @@ class Line(ModelSQL, ModelView):
cls.check_modify(lines)
moves = [x.move for x in lines]
super(Line, cls).delete(lines)
- Move.validate(moves)
+ Move.validate_move(moves)
@classmethod
def write(cls, lines, vals):
@@ -1201,7 +1263,7 @@ class Line(ModelSQL, ModelView):
Transaction().timestamp = {}
- Move.validate(list(set(l.move for l in lines) | set(moves)))
+ Move.validate_move(list(set(l.move for l in lines) | set(moves)))
@classmethod
def create(cls, vlist):
@@ -1240,7 +1302,7 @@ class Line(ModelSQL, ModelView):
for line in lines)
for period, journal in period_and_journals:
cls.check_journal_period_modify(period, journal)
- Move.validate(list(set(line.move for line in lines)))
+ Move.validate_move(list(set(line.move for line in lines)))
return lines
@classmethod
diff --git a/period.py b/period.py
index b4ffed355c..0491e0e6a6 100644
--- a/period.py
+++ b/period.py
@@ -55,32 +55,31 @@ class Period(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(Period, cls).__setup__()
- cls._constraints += [
- ('check_dates', 'periods_overlaps'),
- ('check_fiscalyear_dates', 'fiscalyear_dates'),
- ('check_post_move_sequence', 'check_move_sequence'),
- ]
cls._order.insert(0, ('start_date', 'ASC'))
cls._error_messages.update({
- 'no_period_date': 'No period defined for this date!',
- 'modify_del_period_moves': ('You can not modify/delete '
- 'a period with moves!'),
- 'create_period_closed_fiscalyear': ('You can not create '
- 'a period on a closed fiscal year!'),
- 'open_period_closed_fiscalyear': ('You can not open '
- 'a period from a closed fiscal year!'),
- 'change_post_move_sequence': ('You can not change '
- 'the post move sequence '
- 'if there is already posted moves in the period'),
- 'close_period_non_posted_move': ('You can not close '
- 'a period with non posted moves!'),
- 'periods_overlaps': 'You can not have two overlapping periods!',
- 'check_move_sequence': ('You must have different '
- 'post move sequences per fiscal year '
- 'and in the same company!'),
- 'fiscalyear_dates': ('The period dates must be in '
- 'the fiscal year dates'),
- })
+ 'no_period_date': 'No period defined for date "%s".',
+ 'modify_del_period_moves': ('You can not modify/delete '
+ 'period "%s" because it has moves.'),
+ 'create_period_closed_fiscalyear': ('You can not create '
+ 'a period on fiscal year "%s" because it is closed.'),
+ 'open_period_closed_fiscalyear': ('You can not open period '
+ '"%(period)s" because its fiscal year "%(fiscalyear)s" is '
+ 'closed.'),
+ 'change_post_move_sequence': ('You can not change the post '
+ 'move sequence of period "%s" because there are already '
+ 'posted moves in the period.'),
+ 'close_period_non_posted_move': ('You can not close period '
+ '"%s" because there are non posted moves in this period.'),
+ 'periods_overlap': ('"%(first)s" and "%(second)s" periods '
+ 'overlap.'),
+ 'check_move_sequence': ('Period "%(first)s" and "%(second)s" '
+ 'have the same sequence.'),
+ 'check_move_sequence_company': ('Company of sequence '
+ '"%(sequence)s" does not match the company of period '
+ '"%(period)s" to which it is assigned to.'),
+ 'fiscalyear_dates': ('Dates of period "%s" are outside '
+ 'are outside it\'s fiscal year dates.'),
+ })
@staticmethod
def default_state():
@@ -97,6 +96,14 @@ class Period(ModelSQL, ModelView):
def search_company(cls, name, clause):
return [('fiscalyear.%s' % name,) + tuple(clause[1:])]
+ @classmethod
+ def validate(cls, periods):
+ super(Period, cls).validate(periods)
+ for period in periods:
+ period.check_dates()
+ period.check_fiscalyear_dates()
+ period.check_post_move_sequence()
+
def check_dates(self):
cursor = Transaction().cursor
if self.type != 'standard':
@@ -113,25 +120,37 @@ class Period(ModelSQL, ModelView):
self.end_date, self.end_date,
self.start_date, self.end_date,
self.fiscalyear.id, self.id))
- return not cursor.fetchone()
+ period_id = cursor.fetchone()
+ if period_id:
+ overlapping_period = self.__class__(period_id[0])
+ self.raise_user_error('periods_overlap', {
+ 'first': self.rec_name,
+ 'second': overlapping_period.rec_name,
+ })
def check_fiscalyear_dates(self):
- return not (self.start_date < self.fiscalyear.start_date
- or self.end_date > self.fiscalyear.end_date)
+ if (self.start_date < self.fiscalyear.start_date
+ or self.end_date > self.fiscalyear.end_date):
+ self.raise_user_error('fiscalyear_dates', (self.rec_name,))
def check_post_move_sequence(self):
if not self.post_move_sequence:
- return True
- if self.search([
- ('post_move_sequence', '=', self.post_move_sequence.id),
- ('fiscalyear', '!=', self.fiscalyear.id),
- ]):
- return False
- if (self.post_move_sequence.company
- and (self.post_move_sequence.company.id !=
- self.fiscalyear.company.id)):
- return False
- return True
+ return
+ periods = self.search([
+ ('post_move_sequence', '=', self.post_move_sequence.id),
+ ('fiscalyear', '!=', self.fiscalyear.id),
+ ])
+ if periods:
+ self.raise_user_error('check_move_sequence', {
+ 'first': self.rec_name,
+ 'second': periods[0].rec_name,
+ })
+ if (self.post_move_sequence.company and
+ self.post_move_sequence.company != self.fiscalyear.company):
+ self.raise_user_error('check_move_sequence_company', {
+ 'sequence': self.post_move_sequence.rec_name,
+ 'period': self.rec_name,
+ })
@classmethod
def find(cls, company_id, date=None, exception=True, test_state=True):
@@ -142,7 +161,9 @@ class Period(ModelSQL, ModelView):
if no period is found.
If test_state is true, it will search on non-closed periods
'''
- Date = Pool().get('ir.date')
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Lang = pool.get('ir.lang')
if not date:
date = Date.today()
@@ -157,7 +178,14 @@ class Period(ModelSQL, ModelView):
periods = cls.search(clause, order=[('start_date', 'DESC')], limit=1)
if not periods:
if exception:
- cls.raise_user_error('no_period_date')
+ language = Transaction().language
+ languages = Lang.search([('code', '=', language)])
+ if not languages:
+ languages = Lang.search([('code', '=', 'en_US')])
+ language = languages[0]
+ formatted = Lang.strftime(date, language.code,
+ language.date)
+ cls.raise_user_error('no_period_date', (formatted,))
else:
return None
return periods[0].id
@@ -169,7 +197,8 @@ class Period(ModelSQL, ModelView):
('period', 'in', [p.id for p in periods]),
], limit=1)
if moves:
- cls.raise_user_error('modify_del_period_moves')
+ cls.raise_user_error('modify_del_period_moves', (
+ moves[0].period.rec_name,))
@classmethod
def search(cls, args, offset=0, limit=None, order=None, count=False,
@@ -206,7 +235,8 @@ class Period(ModelSQL, ModelView):
if vals.get('fiscalyear'):
fiscalyear = FiscalYear(vals['fiscalyear'])
if fiscalyear.state == 'close':
- cls.raise_user_error('create_period_closed_fiscalyear')
+ cls.raise_user_error('create_period_closed_fiscalyear',
+ (fiscalyear.rec_name,))
if not vals.get('post_move_sequence'):
vals['post_move_sequence'] = (
fiscalyear.post_move_sequence.id)
@@ -222,7 +252,10 @@ class Period(ModelSQL, ModelView):
if vals.get('state') == 'open':
for period in periods:
if period.fiscalyear.state == 'close':
- cls.raise_user_error('open_period_closed_fiscalyear')
+ cls.raise_user_error('open_period_closed_fiscalyear', {
+ 'period': period.rec_name,
+ 'fiscalyear': period.fiscalyear.rec_name,
+ })
if vals.get('post_move_sequence'):
for period in periods:
if period.post_move_sequence and \
@@ -232,7 +265,8 @@ class Period(ModelSQL, ModelView):
('period', '=', period.id),
('state', '=', 'posted'),
]):
- cls.raise_user_error('change_post_move_sequence')
+ cls.raise_user_error('change_post_move_sequence',
+ (period.rec_name,))
super(Period, cls).write(periods, vals)
@classmethod
@@ -250,7 +284,8 @@ class Period(ModelSQL, ModelView):
('period', 'in', [p.id for p in periods]),
('state', '!=', 'posted'),
]):
- cls.raise_user_error('close_period_non_posted_move')
+ cls.raise_user_error('close_period_non_posted_move',
+ (period.rec_name,))
#First close the period to be sure
#it will not have new journal.period created between.
cls.write(periods, {
diff --git a/tax.py b/tax.py
index 2d68bd1e14..3746d2cf25 100644
--- a/tax.py
+++ b/tax.py
@@ -58,16 +58,14 @@ class TaxCodeTemplate(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(TaxCodeTemplate, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_tax_code'),
- ]
- cls._error_messages.update({
- 'recursive_tax_code': (
- 'You can not create recursive tax codes!'),
- })
cls._order.insert(0, ('code', 'ASC'))
cls._order.insert(0, ('account', 'ASC'))
+ @classmethod
+ def validate(cls, templates):
+ super(CodeTemplate, cls).validate(templates)
+ cls.check_recursion(templates)
+
def _get_tax_code_value(self, code=None):
'''
Set values for tax code creation.
@@ -159,15 +157,13 @@ class TaxCode(ModelSQL, ModelView):
@classmethod
def __setup__(cls):
super(TaxCode, cls).__setup__()
- cls._constraints += [
- ('check_recursion', 'recursive_tax_code'),
- ]
- cls._error_messages.update({
- 'recursive_tax_code': (
- 'You can not create recursive tax codes!'),
- })
cls._order.insert(0, ('code', 'ASC'))
+ @classmethod
+ def validate(cls, codes):
+ super(TaxCode, cls).validate(codes)
+ cls.check_recursion(codes)
+
@staticmethod
def default_active():
return True
diff --git a/tax.xml b/tax.xml
index d9e09a295c..50d7195f15 100644
--- a/tax.xml
+++ b/tax.xml
@@ -506,5 +506,23 @@ this repository contains the full copyright notices and license terms. -->
+
+ account.tax.code
+ en_US
+ error
+ recursion_error
+ Recursion error: Tax Code "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+
+
+ account.tax.code.template
+ en_US
+ error
+ recursion_error
+ Recursion error: Tax Code Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.
+ account
+
+