Replace _constraints with validate in ModelStorage and improve user messages.
issue2616 review371002
This commit is contained in:
1 parent
5dcabe9a7f
commit
7f9c38ee89
8 files changed
+384
-211
No files matched your search
+34
-33
@@ -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):
|
||||
|
||||
+36
@@ -703,5 +703,41 @@ this repository contains the full copyright notices and license terms. -->
|
||||
id="menu_aged_balance" icon="tryton-print"
|
||||
name="Aged Balance"/>
|
||||
|
||||
<record model="ir.translation" id="account_type_template_recursion_error">
|
||||
<field name="name">account.account.type.template</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Account Type Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="account_type_recursion_error">
|
||||
<field name="name">account.account.type</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Account Type "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="account_template_recursion_error">
|
||||
<field name="name">account.account.template</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Account Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="account_recursion_error">
|
||||
<field name="name">account.account</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Account "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
+50
-31
@@ -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.
|
||||
|
||||
+18
-12
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -506,5 +506,23 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.translation" id="tax_code_recursion_error">
|
||||
<field name="name">account.tax.code</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Tax Code "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="tax_code_template_recursion_error">
|
||||
<field name="name">account.tax.code.template</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">recursion_error</field>
|
||||
<field name="value">Recursion error: Tax Code Template "%(rec_name)s" with parent "%(parent_rec_name)s" was configured as ancestor of itself.</field>
|
||||
<field name="module">account</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
Reference in new issue
Block a user