Files
tryton/period.py
T

300 lines
12 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.
'Period'
from trytond.model import ModelView, ModelSQL, fields
from trytond.wizard import Wizard
_STATES = {
'readonly': "state == 'close'",
}
class Period(ModelSQL, ModelView):
'Period'
_name = 'account.period'
_description = __doc__
name = fields.Char('Name', required=True)
code = fields.Char('Code')
start_date = fields.Date('Starting Date', required=True, states=_STATES,
select=1)
end_date = fields.Date('Ending Date', required=True, states=_STATES,
select=1)
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
required=True, states=_STATES, select=1)
state = fields.Selection([
('open', 'Open'),
('close', 'Close'),
], 'State', readonly=True, required=True)
post_move_sequence =fields.Many2One('ir.sequence', 'Post Move Sequence',
required=True, domain=[('code', '=', 'account.move')],
context={'code': 'account.move'})
type = fields.Selection([
('standard', 'Standard'),
('adjustment', 'Adjustment'),
], 'Type', required=True, states=_STATES, select=1)
def __init__(self):
super(Period, self).__init__()
self._constraints += [
('check_dates', 'periods_overlaps'),
('check_fiscalyear_dates', 'fiscalyear_dates'),
('check_post_move_sequence', 'check_move_sequence'),
]
self._order.insert(0, ('start_date', 'ASC'))
self._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',
})
def default_state(self, cursor, user, context=None):
return 'open'
def default_type(self, cursor, user, context=None):
return 'standard'
def check_dates(self, cursor, user, ids):
for period in self.browse(cursor, user, ids):
if period.type != 'standard':
continue
cursor.execute('SELECT id ' \
'FROM "' + self._table + '" ' \
'WHERE ((start_date <= %s AND end_date >= %s) ' \
'OR (start_date <= %s AND end_date >= %s) ' \
'OR (start_date >= %s AND end_date <= %s)) ' \
'AND fiscalyear = %s ' \
'AND type = \'standard\' ' \
'AND id != %s',
(period.start_date, period.start_date,
period.end_date, period.end_date,
period.start_date, period.end_date,
period.fiscalyear.id, period.id))
if cursor.fetchone():
return False
return True
def check_fiscalyear_dates(self, cursor, user, ids):
for period in self.browse(cursor, user, ids):
if period.start_date < period.fiscalyear.start_date \
or period.end_date > period.fiscalyear.end_date:
return False
return True
def check_post_move_sequence(self, cursor, user, ids):
for period in self.browse(cursor, user, ids):
if self.search(cursor, user, [
('post_move_sequence', '=', period.post_move_sequence.id),
('fiscalyear', '!=', period.fiscalyear.id),
]):
return False
if period.post_move_sequence.company \
and period.post_move_sequence.company.id != \
period.fiscalyear.company.id:
return False
return True
def find(self, cursor, user, company_id, date=None, exception=True,
test_state=True, context=None):
'''
Return the period for the company_id
at the date or the current date.
If exception is set the function will raise an exception
if any period is found.
:param cursor: the database cursor
:param user: the user id
:param company_id: the company id
:param date: the date searched
:param exception: a boolean to raise or not an exception
:param test_state: a boolean if true will search on non-closed periods
:param context: the context
:return: the period id found or False
'''
date_obj = self.pool.get('ir.date')
if not date:
date = date_obj.today(cursor, user, context=context)
clause = [
('start_date', '<=', date),
('end_date', '>=', date),
('fiscalyear.company', '=', company_id),
('type', '=', 'standard'),
]
if test_state:
clause.append(('state', '!=', 'close'))
ids = self.search(cursor, user, clause, order=[('start_date', 'DESC')],
limit=1, context=context)
if not ids:
if exception:
self.raise_user_error(cursor, 'no_period_date',
context=context)
else:
return False
return ids[0]
def _check(self, cursor, user, ids, context=None):
move_obj = self.pool.get('account.move')
if isinstance(ids, (int, long)):
ids = [ids]
move_ids = move_obj.search(cursor, user, [
('period', 'in', ids),
], limit=1, context=context)
if move_ids:
self.raise_user_error(cursor, 'modify_del_period_moves',
context=context)
return
def search(self, cursor, user, args, offset=0, limit=None, order=None,
context=None, count=False, query_string=False):
args = args[:]
def process_args(args):
i = 0
while i < len(args):
if isinstance(args[i], list):
process_args(args[i])
if isinstance(args[i], tuple) \
and args[i][0] in ('start_date', 'end_date') \
and isinstance(args[i][2], (list, tuple)):
if not args[i][2][0]:
args[i] = ('id', '!=', '0')
else:
period = self.browse(cursor, user, args[i][2][0],
context=context)
args[i] = (args[i][0], args[i][1], period[args[i][2][1]])
i += 1
process_args(args)
return super(Period, self).search(cursor, user, args, offset=offset,
limit=limit, order=order, context=context, count=count,
query_string=query_string)
def create(self, cursor, user, vals, context=None):
fiscalyear_obj = self.pool.get('account.fiscalyear')
vals = vals.copy()
if vals.get('fiscalyear'):
fiscalyear = fiscalyear_obj.browse(cursor, user, vals['fiscalyear'],
context=context)
if fiscalyear.state == 'close':
self.raise_user_error(cursor,
'create_period_closed_fiscalyear', context=context)
if not vals.get('post_move_sequence'):
vals['post_move_sequence'] = fiscalyear.post_move_sequence.id
return super(Period, self).create(cursor, user, vals, context=context)
def write(self, cursor, user, ids, vals, context=None):
move_obj = self.pool.get('account.move')
for key in vals.keys():
if key in ('start_date', 'end_date', 'fiscalyear'):
self._check(cursor, user, ids, context=context)
break
if vals.get('state') == 'open':
for period in self.browse(cursor, user, ids,
context=context):
if period.fiscalyear.state == 'close':
self.raise_user_error(cursor,
'open_period_closed_fiscalyear', context=context)
if vals.get('post_move_sequence'):
for period in self.browse(cursor, user, ids, context=context):
if period.post_move_sequence and \
period.post_move_sequence.id != \
vals['post_move_sequence']:
if move_obj.search(cursor, user, [
('period', '=', period.id),
('state', '=', 'posted'),
], context=context):
self.raise_user_error(cursor,
'change_post_move_sequence', context=context)
return super(Period, self).write(cursor, user, ids, vals,
context=context)
def delete(self, cursor, user, ids, context=None):
self._check(cursor, user, ids, context=context)
return super(Period, self).delete(cursor, user, ids,
context=context)
def close(self, cursor, user, ids, context=None):
journal_period_obj = self.pool.get('account.journal.period')
move_obj = self.pool.get('account.move')
if isinstance(ids, (int, long)):
ids = [ids]
if move_obj.search(cursor, user, [
('period', 'in', ids),
('state', '!=', 'posted'),
], context=context):
self.raise_user_error(cursor, 'close_period_non_posted_move',
context=context)
#First close the period to be sure
#it will not have new journal.period created between.
self.write(cursor, user, ids, {
'state': 'close',
}, context=context)
journal_period_ids = journal_period_obj.search(cursor, user, [
('period', 'in', ids),
], context=context)
journal_period_obj.close(cursor, user, journal_period_ids,
context=context)
return
Period()
class ClosePeriod(Wizard):
'Close Period'
_name = 'account.period.close_period'
states = {
'init': {
'actions': ['_close'],
'result': {
'type': 'state',
'state': 'end',
},
},
}
def _close(self, cursor, user, data, context=None):
period_obj = self.pool.get('account.period')
period_obj.close(cursor, user, data['ids'], context=context)
return {}
ClosePeriod()
class ReOpenPeriod(Wizard):
'Re-Open Period'
_name = 'account.period.reopen_period'
states = {
'init': {
'actions': ['_reopen'],
'result': {
'type': 'state',
'state': 'end',
},
},
}
def _reopen(self, cursor, user, data, context=None):
period_obj = self.pool.get('account.period')
period_obj.write(cursor, user, data['ids'], {
'state': 'open',
}, context=context)
return {}
ReOpenPeriod()