236 lines
8.9 KiB
Python
236 lines
8.9 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.osv import fields, OSV, ExceptORM
|
|
from trytond.wizard import Wizard
|
|
import datetime
|
|
|
|
_STATES = {
|
|
'readonly': "state == 'close'",
|
|
}
|
|
|
|
|
|
class Period(OSV):
|
|
'Period'
|
|
_name = 'account.period'
|
|
_description = __doc__
|
|
|
|
name = fields.Char('Name', size=None, required=True)
|
|
code = fields.Char('Code', size=None)
|
|
start_date = fields.Date('Starting Date', required=True, states=_STATES)
|
|
end_date = fields.Date('Ending Date', required=True, states=_STATES)
|
|
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
|
|
required=True, states=_STATES)
|
|
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')]")
|
|
|
|
def __init__(self):
|
|
super(Period, self).__init__()
|
|
self._constraints += [
|
|
('check_dates',
|
|
'Error! You can not have 2 periods that overlaps!',
|
|
['start_date', 'end_date']),
|
|
('check_post_move_sequence',
|
|
'Error! You must have different post move sequence ' \
|
|
'per fiscal year!', ['post_move_sequence']),
|
|
]
|
|
self._order.insert(0, ('start_date', 'ASC'))
|
|
|
|
def default_state(self, cursor, user, context=None):
|
|
return 'open'
|
|
|
|
def check_dates(self, cursor, user, ids):
|
|
for period in self.browse(cursor, user, ids):
|
|
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 id != %s',
|
|
(period.start_date, period.start_date,
|
|
period.end_date, period.end_date,
|
|
period.start_date, period.end_date,
|
|
period.id))
|
|
if cursor.rowcount:
|
|
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
|
|
return True
|
|
|
|
def find(self, cursor, user, company_id, date=None, exception=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.
|
|
'''
|
|
if not date:
|
|
date = datetime.date.today()
|
|
ids = self.search(cursor, user, [
|
|
('start_date', '<=', date),
|
|
('end_date', '>=', date),
|
|
('fiscalyear.company', '=', company_id),
|
|
], order=[('start_date', 'DESC')], limit=1, context=context)
|
|
if not ids:
|
|
if exception:
|
|
raise ExceptORM('Error', 'No period defined for this date!')
|
|
else:
|
|
return False
|
|
return ids[0]
|
|
|
|
def _check(self, cursor, user, ids, context=None):
|
|
move_obj = self.pool.get('account.move')
|
|
move_ids = move_obj.search(cursor, user, [
|
|
('period', 'in', ids),
|
|
], limit=1, context=context)
|
|
if move_ids:
|
|
raise ExceptORM('UserError', 'You can not modify/delete ' \
|
|
'a period with moves!')
|
|
return
|
|
|
|
def search(self, cursor, user, args, offset=0, limit=None, order=None,
|
|
context=None, count=False, query_string=False):
|
|
args = args[:]
|
|
i = 0
|
|
while i < len(args):
|
|
if args[i][0] in ('start_date', 'end_date'):
|
|
if 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
|
|
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':
|
|
raise ExceptORM('UserError', 'You can not create ' \
|
|
'a period on a closed fiscal year!')
|
|
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':
|
|
raise ExceptORM('UserError', 'You can not open ' \
|
|
'a period from a closed fiscal year!')
|
|
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):
|
|
raise ExceptORM('UserError', 'You can not change ' \
|
|
'the post move sequence \n' \
|
|
'if there is already posted move in the period')
|
|
return super(Period, self).write(cursor, user, ids, vals,
|
|
context=context)
|
|
|
|
def unlink(self, cursor, user, ids, context=None):
|
|
self._check(cursor, user, ids, context=context)
|
|
return super(Period, self).unlink(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):
|
|
raise ExceptORM('UserError', 'You can not close ' \
|
|
'a period with non posted moves!')
|
|
#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()
|