Files
tryton/move.py
T

1763 lines
69 KiB
Python
Raw Normal View History

2008-10-22 20:07:57 +02:00
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
2008-03-17 18:32:06 +01:00
from decimal import Decimal
import datetime
2013-02-23 14:09:33 +01:00
from itertools import groupby
from operator import itemgetter
2013-09-06 22:33:47 +02:00
from sql.aggregate import Sum
from sql.conditionals import Coalesce
2010-08-19 22:02:00 +02:00
from trytond.model import ModelView, ModelSQL, fields
2012-01-02 17:54:33 +01:00
from trytond.wizard import Wizard, StateTransition, StateView, StateAction, \
Button
2010-08-19 22:02:00 +02:00
from trytond.report import Report
2013-09-06 22:33:47 +02:00
from trytond import backend
2011-08-21 11:20:29 +02:00
from trytond.pyson import Eval, PYSONEncoder
2010-08-19 22:02:00 +02:00
from trytond.transaction import Transaction
2012-09-24 22:17:29 +02:00
from trytond.pool import Pool, PoolMeta
from trytond.rpc import RPC
2013-02-23 14:09:33 +01:00
from trytond.tools import reduce_ids
2012-09-24 22:17:29 +02:00
2013-05-21 19:09:37 +02:00
__all__ = ['Move', 'Reconciliation', 'Line', 'OpenJournalAsk',
2012-09-24 22:17:29 +02:00
'OpenJournal', 'OpenAccount', 'ReconcileLinesWriteOff', 'ReconcileLines',
'UnreconcileLinesStart', 'UnreconcileLines', 'OpenReconcileLinesStart',
'OpenReconcileLines', 'FiscalYearLine', 'FiscalYear2',
'PrintGeneralJournalStart', 'PrintGeneralJournal', 'GeneralJournal']
__metaclass__ = PoolMeta
2008-03-17 18:32:06 +01:00
_MOVE_STATES = {
2011-08-21 11:20:29 +02:00
'readonly': Eval('state') == 'posted',
}
_MOVE_DEPENDS = ['state']
2008-03-17 18:32:06 +01:00
_LINE_STATES = {
2011-08-21 11:20:29 +02:00
'readonly': Eval('state') == 'valid',
}
_LINE_DEPENDS = ['state']
2008-03-17 18:32:06 +01:00
2009-02-28 16:57:10 +01:00
class Move(ModelSQL, ModelView):
2008-03-17 18:32:06 +01:00
'Account Move'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move'
2012-09-29 15:33:21 +02:00
_rec_name = 'number'
number = fields.Char('Number', required=True, readonly=True)
post_number = fields.Char('Post Number', readonly=True,
help='Also known as Folio Number')
2008-03-17 18:32:06 +01:00
period = fields.Many2One('account.period', 'Period', required=True,
2012-03-05 10:52:56 +01:00
states=_MOVE_STATES, depends=_MOVE_DEPENDS, select=True)
2008-03-17 18:32:06 +01:00
journal = fields.Many2One('account.journal', 'Journal', required=True,
states=_MOVE_STATES, depends=_MOVE_DEPENDS)
date = fields.Date('Effective Date', required=True, states=_MOVE_STATES,
2014-01-26 14:28:46 +01:00
depends=_MOVE_DEPENDS)
2008-03-28 19:49:16 +01:00
post_date = fields.Date('Post Date', readonly=True)
2012-09-29 15:33:21 +02:00
description = fields.Char('Description', states=_MOVE_STATES,
depends=_MOVE_DEPENDS)
origin = fields.Reference('Origin', selection='get_origin',
states=_MOVE_STATES, depends=_MOVE_DEPENDS)
2008-03-17 18:32:06 +01:00
state = fields.Selection([
('draft', 'Draft'),
('posted', 'Posted'),
2012-03-05 10:52:56 +01:00
], 'State', required=True, readonly=True, select=True)
2008-03-17 18:32:06 +01:00
lines = fields.One2Many('account.move.line', 'move', 'Lines',
2009-10-10 13:31:39 +02:00
states=_MOVE_STATES, depends=_MOVE_DEPENDS,
2010-01-20 10:56:33 +01:00
context={
'journal': Eval('journal'),
'period': Eval('period'),
'date': Eval('date'),
})
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(Move, cls).__setup__()
cls._check_modify_exclude = ['state']
cls._order.insert(0, ('date', 'DESC'))
2012-09-29 15:33:21 +02:00
cls._order.insert(1, ('number', 'DESC'))
2012-09-24 22:17:29 +02:00
cls._error_messages.update({
'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.'),
'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.'),
})
2012-09-24 22:17:29 +02:00
cls._buttons.update({
2012-03-25 00:17:23 +01:00
'post': {
'invisible': Eval('state') == 'posted',
},
'draft': {
'invisible': Eval('state') == 'draft',
},
})
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __register__(cls, module_name):
2013-09-06 22:33:47 +02:00
TableHandler = backend.get('TableHandler')
2012-09-29 15:33:21 +02:00
cursor = Transaction().cursor
table = TableHandler(cursor, cls, module_name)
# Migration from 2.4:
# - name renamed into number
# - reference renamed into post_number
if table.column_exist('name'):
table.column_rename('name', 'number')
if table.column_exist('reference'):
table.column_rename('reference', 'post_number')
2012-09-24 22:17:29 +02:00
super(Move, cls).__register__(module_name)
2009-02-02 13:09:08 +01:00
2012-09-24 22:17:29 +02:00
table = TableHandler(cursor, cls, module_name)
2009-03-06 00:45:18 +01:00
table.index_action(['journal', 'period'], 'add')
2008-03-17 18:32:06 +01:00
2010-01-23 11:40:35 +01:00
# Add index on create_date
table.index_action('create_date', action='add')
2012-09-24 22:17:29 +02:00
@staticmethod
def default_period():
Period = Pool().get('account.period')
return Period.find(Transaction().context.get('company'),
exception=False)
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_state():
2008-03-17 18:32:06 +01:00
return 'draft'
2012-09-24 22:17:29 +02:00
@classmethod
def default_date(cls):
pool = Pool()
Period = pool.get('account.period')
Date = pool.get('ir.date')
period_id = cls.default_period()
2009-10-10 13:31:39 +02:00
if period_id:
2012-09-24 22:17:29 +02:00
period = Period(period_id)
2009-10-10 13:31:39 +02:00
return period.start_date
2012-09-24 22:17:29 +02:00
return Date.today()
2008-03-17 18:32:06 +01:00
2014-01-26 14:28:46 +01:00
@fields.depends('period', 'journal', 'date')
2012-09-24 22:17:29 +02:00
def on_change_with_date(self):
Line = Pool().get('account.move.line')
date = self.date
lines = Line.search([
('journal', '=', self.journal),
('period', '=', self.period),
], order=[('id', 'DESC')], limit=1)
if lines:
date = lines[0].date
elif self.period:
date = self.period.start_date
return date
2009-10-10 13:31:39 +02:00
2012-09-29 15:33:21 +02:00
@classmethod
def _get_origin(cls):
'Return list of Model names for origin Reference'
2013-09-16 11:33:24 +02:00
return ['account.fiscalyear']
2012-09-29 15:33:21 +02:00
@classmethod
def get_origin(cls):
Model = Pool().get('ir.model')
models = cls._get_origin()
models = Model.search([
('model', 'in', models),
])
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_company()
move.check_date()
2012-09-24 22:17:29 +02:00
def check_company(self):
company_id = -1
for line in self.lines:
if company_id < 0:
company_id = line.account.company.id
if line.account.company.id != company_id:
self.raise_user_error('company_in_move', (self.rec_name,))
2012-09-24 22:17:29 +02:00
def check_date(self):
if (self.date < self.period.start_date
or self.date > self.period.end_date):
self.raise_user_error('date_outside_period', (self.rec_name,))
2012-09-24 22:17:29 +02:00
@classmethod
def check_modify(cls, moves):
2012-03-02 07:46:19 +00:00
'Check posted moves for modifications.'
2012-09-24 22:17:29 +02:00
for move in moves:
2012-03-02 07:46:19 +00:00
if move.state == 'posted':
cls.raise_user_error('modify_posted_move', (move.rec_name,))
2012-03-02 07:46:19 +00:00
2012-09-24 22:17:29 +02:00
@classmethod
def search_rec_name(cls, name, clause):
2014-01-31 14:06:56 +01:00
return ['OR',
('post_number',) + tuple(clause[1:]),
(cls._rec_name,) + tuple(clause[1:]),
]
2012-09-24 22:17:29 +02:00
@classmethod
2013-12-19 14:44:33 +01:00
def write(cls, *args):
actions = iter(args)
all_moves = []
args = []
for moves, values in zip(actions, actions):
keys = values.keys()
for key in cls._check_modify_exclude:
if key in keys:
keys.remove(key)
if len(keys):
cls.check_modify(moves)
args.extend((moves, values))
all_moves.extend(moves)
super(Move, cls).write(*args)
cls.validate_move(all_moves)
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-01-06 22:18:13 +01:00
def create(cls, vlist):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Sequence = pool.get('ir.sequence')
Journal = pool.get('account.journal')
2013-01-06 22:18:13 +01:00
vlist = [x.copy() for x in vlist]
for vals in vlist:
if not vals.get('number'):
journal_id = (vals.get('journal')
or Transaction().context.get('journal'))
if journal_id:
journal = Journal(journal_id)
vals['number'] = Sequence.get_id(journal.sequence.id)
2013-01-06 22:18:13 +01:00
moves = super(Move, cls).create(vlist)
cls.validate_move(moves)
2013-01-06 22:18:13 +01:00
return moves
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def delete(cls, moves):
MoveLine = Pool().get('account.move.line')
cls.check_modify(moves)
MoveLine.delete([l for m in moves for l in m.lines])
super(Move, cls).delete(moves)
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def copy(cls, moves, default=None):
Line = Pool().get('account.move.line')
2008-12-05 13:25:33 +01:00
if default is None:
default = {}
2008-12-05 13:25:33 +01:00
default = default.copy()
2012-09-29 15:33:21 +02:00
default['number'] = None
default['post_number'] = None
2012-09-24 22:17:29 +02:00
default['state'] = cls.default_state()
2012-03-27 10:43:03 +02:00
default['post_date'] = None
default['lines'] = None
2012-09-24 22:17:29 +02:00
new_moves = []
for move in moves:
new_move, = super(Move, cls).copy([move], default=default)
Line.copy(move.lines, default={
'move': new_move.id,
})
new_moves.append(new_move)
return new_moves
2008-12-05 13:25:33 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def validate_move(cls, moves):
2008-03-17 18:32:06 +01:00
'''
2013-05-21 19:09:37 +02:00
Validate balanced move
2008-03-17 18:32:06 +01:00
'''
2012-09-24 22:17:29 +02:00
pool = Pool()
MoveLine = pool.get('account.move.line')
2013-02-23 14:09:33 +01:00
User = pool.get('res.user')
2013-09-06 22:33:47 +02:00
line = MoveLine.__table__()
2013-02-23 14:09:33 +01:00
cursor = Transaction().cursor
if (Transaction().user == 0
and Transaction().context.get('user')):
user = Transaction().context.get('user')
else:
user = Transaction().user
company = User(user).company
amounts = {}
move2draft_lines = {}
for i in range(0, len(moves), cursor.IN_MAX):
sub_moves = moves[i:i + cursor.IN_MAX]
sub_move_ids = [m.id for m in sub_moves]
2013-09-06 22:33:47 +02:00
red_sql = reduce_ids(line.move, sub_move_ids)
2013-02-23 14:09:33 +01:00
2013-09-06 22:33:47 +02:00
cursor.execute(*line.select(line.move,
Sum(line.debit - line.credit),
where=red_sql,
group_by=line.move))
2013-02-23 14:09:33 +01:00
amounts.update(dict(cursor.fetchall()))
2013-09-06 22:33:47 +02:00
cursor.execute(*line.select(line.move, line.id,
where=red_sql & (line.state == 'draft'),
order_by=line.move))
2013-02-23 14:09:33 +01:00
move2draft_lines.update(dict((k, (j[1] for j in g))
for k, g in groupby(cursor.fetchall(), itemgetter(0))))
valid_moves = []
draft_moves = []
2012-09-24 22:17:29 +02:00
for move in moves:
2013-02-23 14:09:33 +01:00
if move.id not in amounts:
2008-03-17 18:32:06 +01:00
continue
2013-02-23 14:09:33 +01:00
amount = amounts[move.id]
2013-02-24 10:15:11 +01:00
# SQLite uses float for SUM
if not isinstance(amount, Decimal):
amount = Decimal(amount)
2013-02-23 14:09:33 +01:00
draft_lines = MoveLine.browse(
list(move2draft_lines.get(move.id, [])))
2012-09-24 22:17:29 +02:00
if not company.currency.is_zero(amount):
2013-05-21 19:09:37 +02:00
draft_moves.append(move.id)
2008-03-17 18:32:06 +01:00
continue
if not draft_lines:
continue
2013-02-23 14:09:33 +01:00
valid_moves.append(move.id)
for move_ids, state in (
(valid_moves, 'valid'),
(draft_moves, 'draft'),
):
if move_ids:
for i in range(0, len(move_ids), cursor.IN_MAX):
sub_ids = move_ids[i:i + cursor.IN_MAX]
2013-09-06 22:33:47 +02:00
red_sql = reduce_ids(line.move, sub_ids)
2013-02-23 14:09:33 +01:00
# Use SQL to prevent double validate loop
2013-09-06 22:33:47 +02:00
cursor.execute(*line.update(
columns=[line.state],
values=[state],
where=red_sql))
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2012-03-25 00:17:23 +01:00
@ModelView.button
2012-09-24 22:17:29 +02:00
def post(cls, moves):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Sequence = pool.get('ir.sequence')
Date = pool.get('ir.date')
Line = pool.get('account.move.line')
2008-04-10 11:22:16 +02:00
2008-03-17 18:32:06 +01:00
for move in moves:
amount = Decimal('0.0')
2008-03-28 19:49:16 +01:00
if not move.lines:
cls.raise_user_error('post_empty_move', (move.rec_name,))
2008-03-17 18:32:06 +01:00
company = None
for line in move.lines:
amount += line.debit - line.credit
if not company:
company = line.account.company
2012-09-24 22:17:29 +02:00
if not company.currency.is_zero(amount):
cls.raise_user_error('post_unbalanced_move', (move.rec_name,))
2008-03-17 18:32:06 +01:00
for move in moves:
values = {
2008-03-17 18:32:06 +01:00
'state': 'posted',
}
if not move.post_number:
values['post_date'] = Date.today()
values['post_number'] = Sequence.get_id(
2013-01-22 16:14:24 +01:00
move.period.post_move_sequence_used.id)
cls.write([move], values)
2008-03-17 18:32:06 +01:00
to_reconcile = [l for l in move.lines
if ((line.debit == line.credit == Decimal('0'))
and line.account.reconcile)]
if to_reconcile:
Line.reconcile(to_reconcile)
2012-09-24 22:17:29 +02:00
@classmethod
2012-03-25 00:17:23 +01:00
@ModelView.button
2012-09-24 22:17:29 +02:00
def draft(cls, moves):
for move in moves:
2008-03-17 18:32:06 +01:00
if not move.journal.update_posted:
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', {
'move': move.rec_name,
'period': move.period.rec_name,
})
cls.write(moves, {
2008-03-17 18:32:06 +01:00
'state': 'draft',
2010-08-19 22:02:00 +02:00
})
2008-03-17 18:32:06 +01:00
2009-02-28 16:57:10 +01:00
class Reconciliation(ModelSQL, ModelView):
2008-03-19 22:13:51 +01:00
'Account Move Reconciliation Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.reconciliation'
2008-03-19 22:13:51 +01:00
name = fields.Char('Name', size=None, required=True)
lines = fields.One2Many('account.move.line', 'reconciliation',
'Lines')
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(Reconciliation, cls).__setup__()
cls._error_messages.update({
'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".'),
2013-10-05 12:16:23 +02:00
'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.'),
})
2008-03-19 22:13:51 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-01-06 22:18:13 +01:00
def create(cls, vlist):
2012-09-24 22:17:29 +02:00
Sequence = Pool().get('ir.sequence')
2013-01-06 22:18:13 +01:00
vlist = [x.copy() for x in vlist]
for vals in vlist:
if 'name' not in vals:
vals['name'] = Sequence.get('account.move.reconciliation')
2013-01-06 22:18:13 +01:00
return super(Reconciliation, cls).create(vlist)
2008-03-19 22:13:51 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-12-19 14:44:33 +01:00
def write(cls, moves, values, *args):
2012-09-24 22:17:29 +02:00
cls.raise_user_error('modify')
@classmethod
def validate(cls, reconciliations):
super(Reconciliation, cls).validate(reconciliations)
cls.check_lines(reconciliations)
2012-09-24 22:17:29 +02:00
@classmethod
def check_lines(cls, reconciliations):
Lang = Pool().get('ir.lang')
2012-09-24 22:17:29 +02:00
for reconciliation in reconciliations:
debit = Decimal('0.0')
credit = Decimal('0.0')
2008-03-19 22:13:51 +01:00
account = None
party = None
2008-03-19 22:13:51 +01:00
for line in reconciliation.lines:
if line.state != 'valid':
cls.raise_user_error('reconciliation_line_not_valid',
(line.rec_name,))
debit += line.debit
credit += line.credit
2008-03-19 22:13:51 +01:00
if not account:
account = line.account
elif account.id != line.account.id:
cls.raise_user_error('reconciliation_different_accounts', {
'line': line.rec_name,
'account1': line.account.rec_name,
'account2': account.rec_name,
})
if not account.reconcile:
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:
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(
language, debit, account.company.currency)
credit = Lang.currency(
language, credit, account.company.currency)
cls.raise_user_error('reconciliation_unbalanced', {
'debit': debit,
'credit': credit,
})
2008-03-19 22:13:51 +01:00
2009-02-28 16:57:10 +01:00
class Line(ModelSQL, ModelView):
2008-03-17 18:32:06 +01:00
'Account Move Line'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.line'
2010-01-20 10:56:33 +01:00
debit = fields.Numeric('Debit', digits=(16, Eval('currency_digits', 2)),
required=True,
depends=['currency_digits', 'credit', 'tax_lines', 'journal'])
2010-01-20 10:56:33 +01:00
credit = fields.Numeric('Credit', digits=(16, Eval('currency_digits', 2)),
required=True,
depends=['currency_digits', 'debit', 'tax_lines', 'journal'])
2008-03-17 18:32:06 +01:00
account = fields.Many2One('account.account', 'Account', required=True,
domain=[('kind', '!=', 'view')],
2014-01-26 14:28:46 +01:00
select=True)
2012-03-05 10:52:56 +01:00
move = fields.Many2One('account.move', 'Move', select=True, required=True,
2011-08-04 16:57:14 +02:00
states={
'required': False,
2011-08-21 11:20:29 +02:00
'readonly': Eval('state') == 'valid',
2011-08-04 16:57:14 +02:00
},
depends=['state'])
2010-03-11 16:45:27 +01:00
journal = fields.Function(fields.Many2One('account.journal', 'Journal'),
'get_move_field', setter='set_move_field',
searcher='search_move_field')
period = fields.Function(fields.Many2One('account.period', 'Period'),
'get_move_field', setter='set_move_field',
searcher='search_move_field')
date = fields.Function(fields.Date('Effective Date', required=True),
'get_move_field', setter='set_move_field',
searcher='search_move_field')
2012-09-29 15:33:21 +02:00
origin = fields.Function(fields.Reference('Origin',
selection='get_origin'),
'get_move_field', searcher='search_move_field')
description = fields.Char('Description')
2014-02-03 18:12:16 +01:00
move_description = fields.Function(fields.Char('Move Description'),
'get_move_field', setter='set_move_field',
searcher='search_move_field')
2008-03-17 18:32:06 +01:00
amount_second_currency = fields.Numeric('Amount Second Currency',
2010-01-20 10:56:33 +01:00
digits=(16, Eval('second_currency_digits', 2)),
help='The amount expressed in a second currency',
depends=['second_currency_digits'])
2008-05-09 17:24:55 +02:00
second_currency = fields.Many2One('currency.currency', 'Second Currency',
2008-03-17 18:32:06 +01:00
help='The second currency')
2014-01-26 14:28:46 +01:00
party = fields.Many2One('party.party', 'Party', select=True)
maturity_date = fields.Date('Maturity Date',
2013-02-16 18:54:35 +01:00
help='This field is used for payable and receivable lines. \n'
'You can put the limit date for the payment.')
2008-03-17 18:32:06 +01:00
state = fields.Selection([
('draft', 'Draft'),
('valid', 'Valid'),
2012-03-05 10:52:56 +01:00
], 'State', readonly=True, required=True, select=True)
2008-03-19 22:13:51 +01:00
reconciliation = fields.Many2One('account.move.reconciliation',
2012-03-05 10:52:56 +01:00
'Reconciliation', readonly=True, ondelete='SET NULL', select=True)
2008-03-23 23:05:12 +01:00
tax_lines = fields.One2Many('account.tax.line', 'move_line', 'Tax Lines')
2010-03-11 16:45:27 +01:00
move_state = fields.Function(fields.Selection([
('draft', 'Draft'),
('posted', 'Posted'),
], 'Move State'), 'get_move_field', searcher='search_move_field')
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'get_currency_digits')
second_currency_digits = fields.Function(fields.Integer(
'Second Currency Digits'), 'get_currency_digits')
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(Line, cls).__setup__()
cls._check_modify_exclude = ['reconciliation']
2012-09-24 22:17:29 +02:00
cls._sql_constraints += [
2008-03-17 18:32:06 +01:00
('credit_debit',
'CHECK(credit * debit = 0.0)',
'Wrong credit/debit values.'),
2012-09-24 22:17:29 +02:00
]
cls.__rpc__.update({
'on_write': RPC(instantiate=0),
2012-09-29 15:33:21 +02:00
'get_origin': RPC(),
2012-09-24 22:17:29 +02:00
})
cls._order[0] = ('id', 'DESC')
cls._error_messages.update({
'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.'),
2013-10-05 12:16:23 +02:00
'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.'),
2013-10-05 12:16:23 +02:00
'move_inactive_account': ('You can not create a move line '
'with account "%s" because it is inactive.'),
'already_reconciled': 'Line "%s" (%d) already reconciled.',
})
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __register__(cls, module_name):
2013-09-06 22:33:47 +02:00
TableHandler = backend.get('TableHandler')
2012-09-29 15:33:21 +02:00
cursor = Transaction().cursor
table = TableHandler(cursor, cls, module_name)
# Migration from 2.4: reference renamed into description
if table.column_exist('reference'):
table.column_rename('reference', 'description')
2012-09-24 22:17:29 +02:00
super(Line, cls).__register__(module_name)
2012-09-24 22:17:29 +02:00
table = TableHandler(cursor, cls, module_name)
2010-03-12 14:14:53 +01:00
# Index for General Ledger
table.index_action(['move', 'account'], 'add')
# Migration from 1.2
table.not_null_action('blocked', action='remove')
# Migration from 2.4: remove name, active
2012-09-29 15:33:21 +02:00
table.not_null_action('name', action='remove')
table.not_null_action('active', action='remove')
table.index_action('active', action='remove')
2012-09-29 15:33:21 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def default_date(cls):
2008-03-17 18:32:06 +01:00
'''
Return the date of the last line for journal, period
or the starting date of the period
or today
'''
2012-09-24 22:17:29 +02:00
pool = Pool()
Period = pool.get('account.period')
Date = pool.get('ir.date')
2008-10-08 12:17:47 +02:00
2012-09-24 22:17:29 +02:00
date = Date.today()
lines = cls.search([
('journal', '=', Transaction().context.get('journal')),
('period', '=', Transaction().context.get('period')),
], order=[('id', 'DESC')], limit=1)
if lines:
date = lines[0].date
2010-08-19 22:02:00 +02:00
elif Transaction().context.get('period'):
2012-09-24 22:17:29 +02:00
period = Period(Transaction().context['period'])
date = period.start_date
2010-08-19 22:02:00 +02:00
if Transaction().context.get('date'):
2012-09-24 22:17:29 +02:00
date = Transaction().context['date']
return date
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_state():
2008-03-17 18:32:06 +01:00
return 'draft'
2012-09-24 22:17:29 +02:00
@staticmethod
def default_currency_digits():
2009-04-02 13:31:32 +02:00
return 2
2012-09-24 22:17:29 +02:00
@staticmethod
def default_debit():
return Decimal(0)
2012-09-24 22:17:29 +02:00
@staticmethod
def default_credit():
return Decimal(0)
2012-09-24 22:17:29 +02:00
@classmethod
2014-01-26 21:57:41 +01:00
def default_get(cls, fields, with_rec_name=True, with_on_change=True):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Move = pool.get('account.move')
Tax = pool.get('account.tax')
Account = pool.get('account.account')
TaxCode = pool.get('account.tax.code')
values = super(Line, cls).default_get(fields,
2014-01-26 21:57:41 +01:00
with_rec_name=with_rec_name, with_on_change=with_on_change)
2008-03-17 18:32:06 +01:00
if 'move' not in fields:
#Not manual entry
2008-06-06 11:22:06 +02:00
if 'date' in values:
values = values.copy()
del values['date']
2008-03-17 18:32:06 +01:00
return values
2010-08-19 22:02:00 +02:00
if (Transaction().context.get('journal')
and Transaction().context.get('period')):
2012-09-24 22:17:29 +02:00
lines = cls.search([
2010-08-19 22:02:00 +02:00
('move.journal', '=', Transaction().context['journal']),
('move.period', '=', Transaction().context['period']),
('create_uid', '=', Transaction().user),
2008-03-17 18:32:06 +01:00
('state', '=', 'draft'),
2010-08-19 22:02:00 +02:00
], order=[('id', 'DESC')], limit=1)
2012-09-24 22:17:29 +02:00
if not lines:
2008-03-17 18:32:06 +01:00
return values
2012-12-16 23:34:18 +01:00
move = lines[0].move
values['move'] = move.id
values['move.rec_name'] = move.rec_name
2008-03-17 18:32:06 +01:00
if 'move' not in values:
return values
2012-09-24 22:17:29 +02:00
move = Move(values['move'])
2008-03-17 18:32:06 +01:00
total = Decimal('0.0')
taxes = {}
no_code_taxes = []
2008-03-17 18:32:06 +01:00
for line in move.lines:
total += line.debit - line.credit
2012-12-16 23:34:18 +01:00
if line.party and 'party' in fields and 'party' not in values:
values['party'] = line.party.id
values['party.rec_name'] = line.party.rec_name
if move.journal.type in ('expense', 'revenue'):
line_code_taxes = [x.code.id for x in line.tax_lines]
for tax in line.account.taxes:
if move.journal.type == 'revenue':
if line.debit:
2013-04-20 17:03:33 +02:00
base_id = (tax.credit_note_base_code.id
if tax.credit_note_base_code else None)
code_id = (tax.credit_note_tax_code.id
if tax.credit_note_tax_code else None)
account_id = (tax.credit_note_account.id
if tax.credit_note_account else None)
else:
2013-04-20 17:03:33 +02:00
base_id = (tax.invoice_base_code.id
if tax.invoice_base_code else None)
code_id = (tax.invoice_tax_code.id
if tax.invoice_tax_code else None)
account_id = (tax.invoice_account.id
if tax.invoice_account else None)
else:
if line.debit:
2013-04-20 17:03:33 +02:00
base_id = (tax.invoice_base_code.id
if tax.invoice_base_code else None)
code_id = (tax.invoice_tax_code.id
if tax.invoice_tax_code else None)
account_id = (tax.invoice_account.id
if tax.invoice_account else None)
else:
2013-04-20 17:03:33 +02:00
base_id = (tax.credit_note_base_code.id
if tax.credit_note_base_code else None)
code_id = (tax.credit_note_tax_code.id
if tax.credit_note_tax_code else None)
account_id = (tax.credit_note_account.id
if tax.credit_note_account else None)
if base_id in line_code_taxes or not base_id:
2012-03-27 10:43:03 +02:00
taxes.setdefault((account_id, code_id, tax.id), None)
for tax_line in line.tax_lines:
2013-02-16 18:54:35 +01:00
taxes[
(line.account.id, tax_line.code.id, tax_line.tax.id)
] = True
if not line.tax_lines:
no_code_taxes.append(line.account.id)
for no_code_account_id in no_code_taxes:
for (account_id, code_id, tax_id), test in \
taxes.iteritems():
if (not test
and not code_id
and no_code_account_id == account_id):
taxes[(account_id, code_id, tax_id)] = True
2008-03-17 18:32:06 +01:00
if 'account' in fields:
2012-12-16 23:34:18 +01:00
account = None
if total >= Decimal('0.0'):
2012-12-16 23:34:18 +01:00
if move.journal.credit_account:
account = move.journal.credit_account
2008-03-17 18:32:06 +01:00
else:
2012-12-16 23:34:18 +01:00
if move.journal.debit_account:
account = move.journal.debit_account
if account:
values['account'] = account.id
values['account.rec_name'] = account.rec_name
else:
values['account'] = None
2008-03-17 18:32:06 +01:00
if ('debit' in fields) or ('credit' in fields):
values['debit'] = total < 0 and - total or Decimal(0)
values['credit'] = total > 0 and total or Decimal(0)
if move.journal.type in ('expense', 'revenue'):
for account_id, code_id, tax_id in taxes:
if taxes[(account_id, code_id, tax_id)]:
continue
for line in move.lines:
if move.journal.type == 'revenue':
if line.debit:
2008-10-03 17:11:53 +02:00
key = 'credit_note'
else:
key = 'invoice'
else:
if line.debit:
key = 'invoice'
else:
2008-10-03 17:11:53 +02:00
key = 'credit_note'
line_amount = Decimal('0.0')
tax_amount = Decimal('0.0')
2012-09-24 22:17:29 +02:00
for tax_line in Tax.compute(line.account.taxes,
2010-08-19 22:02:00 +02:00
line.debit or line.credit, 1):
2013-04-20 17:03:33 +02:00
tax_account = getattr(tax_line['tax'],
key + '_account')
tax_code = getattr(tax_line['tax'], key + '_tax_code')
if ((tax_account.id if tax_account
else line.account.id) == account_id
and (tax_code.id if tax_code else None
2013-02-16 18:54:35 +01:00
== code_id)
and tax_line['tax'].id == tax_id):
if line.debit:
line_amount += tax_line['amount']
else:
line_amount -= tax_line['amount']
tax_amount += tax_line['amount'] * \
2013-02-16 18:54:35 +01:00
tax_line['tax'][key + '_tax_sign']
2012-09-24 22:17:29 +02:00
line_amount = line.account.company.currency.round(
line_amount)
tax_amount = line.account.company.currency.round(
tax_amount)
if ('debit' in fields):
values['debit'] = line_amount > Decimal('0.0') \
2013-02-16 18:54:35 +01:00
and line_amount or Decimal('0.0')
if ('credit' in fields):
values['credit'] = line_amount < Decimal('0.0') \
2013-02-16 18:54:35 +01:00
and - line_amount or Decimal('0.0')
2013-04-20 17:03:33 +02:00
if 'account' in fields and account_id:
values['account'] = account_id
2012-09-24 22:17:29 +02:00
values['account.rec_name'] = Account(
account_id).rec_name
if 'tax_lines' in fields and code_id:
values['tax_lines'] = [
{
'amount': tax_amount,
'currency_digits': line.currency_digits,
'code': code_id,
2012-09-24 22:17:29 +02:00
'code.rec_name': TaxCode(code_id).rec_name,
'tax': tax_id,
2012-09-24 22:17:29 +02:00
'tax.rec_name': Tax(tax_id).rec_name,
},
]
2008-03-17 18:32:06 +01:00
return values
2012-09-24 22:17:29 +02:00
@classmethod
def get_currency_digits(cls, lines, names):
digits = {}
for line in lines:
2008-09-22 18:23:05 +02:00
for name in names:
2012-09-24 22:17:29 +02:00
digits.setdefault(name, {})
digits[name].setdefault(line.id, 2)
2008-09-22 18:23:05 +02:00
if name == 'currency_digits':
2012-09-24 22:17:29 +02:00
digits[name][line.id] = line.account.currency_digits
2008-09-22 18:23:05 +02:00
elif name == 'second_currency_digits':
2012-04-03 20:06:15 +02:00
second_currency = line.account.second_currency
if second_currency:
2012-09-24 22:17:29 +02:00
digits[name][line.id] = second_currency.digits
return digits
2008-09-22 18:23:05 +02:00
2012-09-29 15:33:21 +02:00
@classmethod
def get_origin(cls):
Move = Pool().get('account.move')
return Move.get_origin()
2014-01-26 14:28:46 +01:00
@fields.depends('account', 'debit', 'credit', 'tax_lines', 'journal',
'move')
2012-09-24 22:17:29 +02:00
def on_change_debit(self):
changes = {}
Journal = Pool().get('account.journal')
if self.journal or Transaction().context.get('journal'):
journal = self.journal or Journal(Transaction().context['journal'])
if journal.type in ('expense', 'revenue'):
2012-09-24 22:17:29 +02:00
changes['tax_lines'] = self._compute_tax_lines(journal.type)
if not changes['tax_lines']:
del changes['tax_lines']
if self.debit:
changes['credit'] = Decimal('0.0')
return changes
2014-01-26 14:28:46 +01:00
@fields.depends('account', 'debit', 'credit', 'tax_lines', 'journal',
'move')
2012-09-24 22:17:29 +02:00
def on_change_credit(self):
changes = {}
Journal = Pool().get('account.journal')
if self.journal or Transaction().context.get('journal'):
journal = self.journal or Journal(Transaction().context['journal'])
if journal.type in ('expense', 'revenue'):
2012-09-24 22:17:29 +02:00
changes['tax_lines'] = self._compute_tax_lines(journal.type)
if not changes['tax_lines']:
del changes['tax_lines']
if self.credit:
changes['debit'] = Decimal('0.0')
return changes
2014-01-26 14:28:46 +01:00
@fields.depends('account', 'debit', 'credit', 'tax_lines', 'journal',
'move')
2012-09-24 22:17:29 +02:00
def on_change_account(self):
Journal = Pool().get('account.journal')
2008-09-22 18:23:05 +02:00
2012-09-24 22:17:29 +02:00
changes = {}
2010-08-19 22:02:00 +02:00
if Transaction().context.get('journal'):
2012-09-24 22:17:29 +02:00
journal = Journal(Transaction().context['journal'])
if journal.type in ('expense', 'revenue'):
2012-09-24 22:17:29 +02:00
changes['tax_lines'] = self._compute_tax_lines(journal.type)
if not changes['tax_lines']:
del changes['tax_lines']
2012-09-24 22:17:29 +02:00
if self.account:
changes['currency_digits'] = self.account.currency_digits
if self.account.second_currency:
changes['second_currency_digits'] = \
self.account.second_currency.digits
return changes
2012-09-24 22:17:29 +02:00
def _compute_tax_lines(self, journal_type):
res = {}
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
TaxCode = pool.get('account.tax.code')
Tax = pool.get('account.tax')
TaxLine = pool.get('account.tax.line')
2012-09-24 22:17:29 +02:00
if self.move:
#Only for first line
return res
2012-09-24 22:17:29 +02:00
if self.tax_lines:
res['remove'] = [x['id'] for x in self.tax_lines]
if self.account:
debit = self.debit or Decimal('0.0')
2013-02-16 18:54:35 +01:00
credit = self.credit or Decimal('0.0')
2012-09-24 22:17:29 +02:00
for tax in self.account.taxes:
if journal_type == 'revenue':
if debit:
2008-10-03 17:11:53 +02:00
key = 'credit_note'
else:
key = 'invoice'
else:
if debit:
key = 'invoice'
else:
2008-10-03 17:11:53 +02:00
key = 'credit_note'
base_amounts = {}
2012-09-24 22:17:29 +02:00
for tax_line in Tax.compute(self.account.taxes,
2010-08-19 22:02:00 +02:00
debit or credit, 1):
2013-04-20 17:03:33 +02:00
code = getattr(tax_line['tax'], key + '_base_code')
code_id = code.id if code else None
if not code_id:
continue
tax_id = tax_line['tax'].id
base_amounts.setdefault((code_id, tax_id), Decimal('0.0'))
base_amounts[code_id, tax_id] += tax_line['base'] * \
2013-04-20 17:03:33 +02:00
getattr(tax_line['tax'], key + '_tax_sign')
for code_id, tax_id in base_amounts:
if not base_amounts[code_id, tax_id]:
continue
2012-09-24 22:17:29 +02:00
value = TaxLine.default_get(TaxLine._fields.keys())
value.update({
'amount': base_amounts[code_id, tax_id],
2012-09-24 22:17:29 +02:00
'currency_digits': self.account.currency_digits,
'code': code_id,
2012-09-24 22:17:29 +02:00
'code.rec_name': TaxCode(code_id).rec_name,
'tax': tax_id,
2012-09-24 22:17:29 +02:00
'tax.rec_name': Tax(tax_id).rec_name,
})
res.setdefault('add', []).append(value)
return res
2014-01-26 14:28:46 +01:00
@fields.depends('move', 'party', 'account', 'debit', 'credit', 'journal')
2012-09-24 22:17:29 +02:00
def on_change_party(self):
Journal = Pool().get('account.journal')
2010-08-19 22:02:00 +02:00
cursor = Transaction().cursor
res = {}
2012-09-24 22:17:29 +02:00
if (not self.party) or self.account:
return res
2012-09-24 22:17:29 +02:00
if not self.party.account_receivable \
or not self.party.account_payable:
return res
if self.party and (not self.debit) and (not self.credit):
2013-09-06 22:33:47 +02:00
type_name = self.__class__.debit.sql_type().base
table = self.__table__()
column = Coalesce(Sum(Coalesce(table.debit, 0)
- Coalesce(table.credit, 0)), 0).cast(type_name)
where = ((table.reconciliation == None)
& (table.party == self.party.id))
cursor.execute(*table.select(column,
where=where
& (table.account == self.party.account_receivable.id)))
2008-03-19 22:13:51 +01:00
amount = cursor.fetchone()[0]
2009-09-22 16:08:11 +02:00
# SQLite uses float for SUM
if not isinstance(amount, Decimal):
2011-10-28 10:28:26 +02:00
amount = Decimal(str(amount))
2012-09-24 22:17:29 +02:00
if not self.party.account_receivable.currency.is_zero(amount):
if amount > Decimal('0.0'):
2012-09-24 22:17:29 +02:00
res['credit'] = \
self.party.account_receivable.currency.round(amount)
2008-03-19 22:13:51 +01:00
res['debit'] = Decimal('0.0')
else:
res['credit'] = Decimal('0.0')
2012-09-24 22:17:29 +02:00
res['debit'] = \
- self.party.account_receivable.currency.round(amount)
res['account'] = self.party.account_receivable.id
res['account.rec_name'] = \
self.party.account_receivable.rec_name
2008-03-19 22:13:51 +01:00
else:
2013-09-06 22:33:47 +02:00
cursor.execute(*table.select(column,
where=where
& (table.account == self.party.account_payable.id)))
2008-03-19 22:13:51 +01:00
amount = cursor.fetchone()[0]
2012-09-24 22:17:29 +02:00
if not self.party.account_payable.currency.is_zero(amount):
if amount > Decimal('0.0'):
2012-09-24 22:17:29 +02:00
res['credit'] = \
self.party.account_payable.currency.round(amount)
2008-03-19 22:13:51 +01:00
res['debit'] = Decimal('0.0')
else:
res['credit'] = Decimal('0.0')
2012-09-24 22:17:29 +02:00
res['debit'] = \
- self.party.account_payable.currency.round(amount)
res['account'] = self.party.account_payable.id
res['account.rec_name'] = \
self.party.account_payable.rec_name
2008-03-19 22:13:51 +01:00
2012-09-24 22:17:29 +02:00
if self.party and self.debit:
if self.debit > Decimal('0.0'):
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_receivable.id
res['account.rec_name'] = \
self.party.account_receivable.rec_name
2008-03-19 22:13:51 +01:00
else:
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_payable.id
res['account.rec_name'] = \
self.party.account_payable.rec_name
2008-03-19 22:13:51 +01:00
2012-09-24 22:17:29 +02:00
if self.party and self.credit:
if self.credit > Decimal('0.0'):
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_payable.id
res['account.rec_name'] = \
self.party.account_payable.rec_name
2008-03-19 22:13:51 +01:00
else:
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_receivable.id
res['account.rec_name'] = \
self.party.account_receivable.rec_name
2008-03-19 22:13:51 +01:00
2012-11-22 23:24:24 +01:00
journal = None
if self.journal:
journal = self.journal
elif Transaction().context.get('journal'):
journal = Journal(Transaction().context.get('journal'))
2012-09-24 22:17:29 +02:00
if journal and self.party:
if journal.type == 'revenue':
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_receivable.id
res['account.rec_name'] = \
self.party.account_receivable.rec_name
elif journal.type == 'expense':
if 'account' not in res:
2012-09-24 22:17:29 +02:00
res['account'] = self.party.account_payable.id
res['account.rec_name'] = \
self.party.account_payable.rec_name
return res
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
def get_move_field(self, name):
2014-02-03 18:12:16 +01:00
if name.startswith('move_'):
name = name[5:]
if name in ('date', 'state', 'description'):
2012-09-24 22:17:29 +02:00
return getattr(self.move, name)
elif name == 'origin':
2012-10-16 16:29:47 +02:00
origin = getattr(self.move, name)
if origin:
return str(origin)
return None
2012-09-24 22:17:29 +02:00
else:
return getattr(self.move, name).id
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def set_move_field(cls, lines, name, value):
2014-02-03 18:12:16 +01:00
if name.startswith('move_'):
name = name[5:]
if not value:
return
2012-09-24 22:17:29 +02:00
Move = Pool().get('account.move')
Move.write([line.move for line in lines], {
name: value,
})
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def search_move_field(cls, name, clause):
2014-02-03 18:12:16 +01:00
if name.startswith('move_'):
name = name[5:]
return [('move.' + name,) + tuple(clause[1:])]
2013-09-17 10:49:25 +02:00
def _order_move_field(name):
def order_field(tables):
pool = Pool()
Move = pool.get('account.move')
field = Move._fields[name]
table, _ = tables[None]
move_tables = tables.get('move')
if move_tables is None:
move = Move.__table__()
move_tables = {
None: (move, move.id == table.move),
}
tables['move'] = move_tables
return field.convert_order(name, move_tables, Move)
return staticmethod(order_field)
order_journal = _order_move_field('journal')
order_period = _order_move_field('period')
order_date = _order_move_field('date')
order_origin = _order_move_field('origin')
order_move_state = _order_move_field('state')
2012-09-24 22:17:29 +02:00
@classmethod
2013-09-06 22:33:47 +02:00
def query_get(cls, table):
2008-03-17 18:32:06 +01:00
'''
2008-09-19 15:00:26 +02:00
Return SQL clause and fiscal years for account move line
depending of the context.
2013-09-06 22:33:47 +02:00
table is the SQL instance of account.move.line table
2008-03-17 18:32:06 +01:00
'''
2013-09-06 22:33:47 +02:00
pool = Pool()
FiscalYear = pool.get('account.fiscalyear')
Move = pool.get('account.move')
Period = pool.get('account.period')
move = Move.__table__()
period = Period.__table__()
2010-08-19 22:02:00 +02:00
if Transaction().context.get('date'):
2012-09-24 22:17:29 +02:00
fiscalyears = FiscalYear.search([
('start_date', '<=', Transaction().context['date']),
('end_date', '>=', Transaction().context['date']),
], limit=1)
2012-09-24 22:17:29 +02:00
fiscalyear_id = fiscalyears and fiscalyears[0].id or 0
2010-08-19 22:02:00 +02:00
if Transaction().context.get('posted'):
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(move.join(period,
condition=move.period == period.id
).select(move.id,
where=(period.fiscalyear == fiscalyear_id)
2013-09-06 22:33:47 +02:00
& (move.date <= Transaction().context['date'])
& (move.state == 'posted'))),
[f.id for f in fiscalyears])
else:
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(move.join(period,
condition=move.period == period.id
).select(move.id,
where=(period.fiscalyear == fiscalyear_id)
& (move.date <= Transaction().context['date']))),
[f.id for f in fiscalyears])
2010-08-19 22:02:00 +02:00
if Transaction().context.get('periods'):
if Transaction().context.get('fiscalyear'):
2013-09-06 22:33:47 +02:00
fiscalyear_ids = [Transaction().context['fiscalyear']]
else:
fiscalyear_ids = []
2010-08-19 22:02:00 +02:00
if Transaction().context.get('posted'):
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(
move.select(move.id,
2013-11-14 13:34:36 +01:00
where=move.period.in_(
2013-09-06 22:33:47 +02:00
Transaction().context['periods'])
2013-11-14 13:34:36 +01:00
& (move.state == 'posted'))),
2013-09-06 22:33:47 +02:00
fiscalyear_ids)
2008-03-28 17:25:14 +01:00
else:
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(
move.select(move.id,
where=move.period.in_(
Transaction().context['periods']))),
fiscalyear_ids)
2008-03-17 18:32:06 +01:00
else:
if not Transaction().context.get('fiscalyear'):
2012-09-24 22:17:29 +02:00
fiscalyears = FiscalYear.search([
('state', '=', 'open'),
])
2013-09-06 22:33:47 +02:00
fiscalyear_ids = [f.id for f in fiscalyears] or [0]
else:
2013-09-06 22:33:47 +02:00
fiscalyear_ids = [Transaction().context.get('fiscalyear')]
2010-08-19 22:02:00 +02:00
if Transaction().context.get('posted'):
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(
move.select(move.id,
where=move.period.in_(
period.select(period.id,
where=period.fiscalyear.in_(
fiscalyear_ids)))
2013-11-14 13:34:36 +01:00
& (move.state == 'posted'))),
2013-09-06 22:33:47 +02:00
fiscalyear_ids)
2008-03-28 17:25:14 +01:00
else:
2013-09-06 22:33:47 +02:00
return ((table.state != 'draft')
& table.move.in_(
move.select(move.id,
where=move.period.in_(
period.select(period.id,
where=period.fiscalyear.in_(
fiscalyear_ids))))),
fiscalyear_ids)
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def on_write(cls, lines):
return list(set(l.id for line in lines for l in line.move.lines))
2008-03-17 18:32:06 +01:00
@classmethod
def validate(cls, lines):
super(Line, cls).validate(lines)
for line in lines:
line.check_account()
2012-09-24 22:17:29 +02:00
def check_account(self):
if self.account.kind in ('view',):
self.raise_user_error('move_view_account', (
self.account.rec_name,))
2012-09-24 22:17:29 +02:00
if not self.account.active:
self.raise_user_error('move_inactive_account', (
self.account.rec_name,))
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def check_journal_period_modify(cls, period, journal):
2008-03-17 18:32:06 +01:00
'''
Check if the lines can be modified or created for the journal - period
and if there is no journal - period, create it
'''
2012-09-24 22:17:29 +02:00
JournalPeriod = Pool().get('account.journal.period')
journal_periods = JournalPeriod.search([
('journal', '=', journal.id),
('period', '=', period.id),
], limit=1)
if journal_periods:
journal_period, = journal_periods
2008-03-17 18:32:06 +01:00
if journal_period.state == 'close':
cls.raise_user_error('add_modify_closed_journal_period', (
journal_period.rec_name,))
2008-03-17 18:32:06 +01:00
else:
2013-01-06 22:18:13 +01:00
JournalPeriod.create([{
'name': journal.name + ' - ' + period.name,
'journal': journal.id,
'period': period.id,
}])
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def check_modify(cls, lines):
2008-03-17 18:32:06 +01:00
'''
Check if the lines can be modified
'''
journal_period_done = []
2012-09-24 22:17:29 +02:00
for line in lines:
2008-03-17 18:32:06 +01:00
if line.move.state == 'posted':
cls.raise_user_error('modify_posted_move', (
line.move.rec_name,))
2008-03-19 22:13:51 +01:00
if line.reconciliation:
cls.raise_user_error('modify_reconciled', (
line.rec_name,))
2008-03-17 18:32:06 +01:00
journal_period = (line.journal.id, line.period.id)
if journal_period not in journal_period_done:
2012-09-24 22:17:29 +02:00
cls.check_journal_period_modify(line.period,
line.journal)
2008-03-17 18:32:06 +01:00
journal_period_done.append(journal_period)
2012-09-24 22:17:29 +02:00
@classmethod
def delete(cls, lines):
Move = Pool().get('account.move')
cls.check_modify(lines)
moves = [x.move for x in lines]
super(Line, cls).delete(lines)
Move.validate_move(moves)
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-12-19 14:44:33 +01:00
def write(cls, *args):
2012-09-24 22:17:29 +02:00
Move = Pool().get('account.move')
2013-12-19 14:44:33 +01:00
actions = iter(args)
args = []
moves = []
all_lines = []
for lines, values in zip(actions, actions):
if any(k not in cls._check_modify_exclude for k in values):
cls.check_modify(lines)
moves.extend((x.move for x in lines))
all_lines.extend(lines)
args.extend((lines, values))
super(Line, cls).write(*args)
2010-08-19 22:02:00 +02:00
Transaction().timestamp = {}
2013-12-19 14:44:33 +01:00
Move.validate_move(list(set(l.move for l in all_lines) | set(moves)))
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-01-06 22:18:13 +01:00
def create(cls, vlist):
2012-09-24 22:17:29 +02:00
pool = Pool()
Journal = pool.get('account.journal')
Move = pool.get('account.move')
2013-01-06 22:18:13 +01:00
vlist = [x.copy() for x in vlist]
for vals in vlist:
if not vals.get('move'):
2013-01-06 22:18:13 +01:00
journal_id = (vals.get('journal')
or Transaction().context.get('journal'))
if not journal_id:
cls.raise_user_error('no_journal')
journal = Journal(journal_id)
if not vals.get('move'):
vals['move'] = Move.create([{
'period': (vals.get('period')
or Transaction().context.get('period')),
'journal': journal_id,
'date': vals.get('date'),
}])[0].id
else:
# prevent computation of default date
vals.setdefault('date', None)
lines = super(Line, cls).create(vlist)
2013-02-16 18:54:35 +01:00
period_and_journals = set((line.period, line.journal)
2013-01-06 22:18:13 +01:00
for line in lines)
for period, journal in period_and_journals:
cls.check_journal_period_modify(period, journal)
Move.validate_move(list(set(line.move for line in lines)))
2013-01-06 22:18:13 +01:00
return lines
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def copy(cls, lines, default=None):
if default is None:
default = {}
if 'move' not in default:
2012-03-27 10:43:03 +02:00
default['move'] = None
if 'reconciliation' not in default:
2012-03-27 10:43:03 +02:00
default['reconciliation'] = None
2012-09-24 22:17:29 +02:00
return super(Line, cls).copy(lines, default=default)
2012-09-24 22:17:29 +02:00
@classmethod
def view_header_get(cls, value, view_type='form'):
JournalPeriod = Pool().get('account.journal.period')
2010-08-19 22:02:00 +02:00
if (not Transaction().context.get('journal')
or not Transaction().context.get('period')):
2009-02-02 13:09:08 +01:00
return value
2012-09-24 22:17:29 +02:00
journal_periods = JournalPeriod.search([
('journal', '=', Transaction().context['journal']),
('period', '=', Transaction().context['period']),
], limit=1)
if not journal_periods:
return value
2012-09-24 22:17:29 +02:00
journal_period, = journal_periods
return value + ': ' + journal_period.rec_name
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def fields_view_get(cls, view_id=None, view_type='form'):
Journal = Pool().get('account.journal')
result = super(Line, cls).fields_view_get(view_id=view_id,
view_type=view_type)
2010-08-19 22:02:00 +02:00
if view_type == 'tree' and 'journal' in Transaction().context:
2012-09-24 22:17:29 +02:00
title = cls.view_header_get('', view_type=view_type)
journal = Journal(Transaction().context['journal'])
2008-03-17 18:32:06 +01:00
if not journal.view:
return result
xml = '<?xml version="1.0"?>\n' \
2013-02-16 18:54:35 +01:00
'<tree string="%s" editable="top" on_write="on_write" ' \
'colors="red:state==\'draft\'">\n' % title
fields = set()
2008-03-17 18:32:06 +01:00
for column in journal.view.columns:
fields.add(column.field.name)
2008-03-17 18:32:06 +01:00
attrs = []
if column.field.name == 'debit':
2008-03-18 17:30:54 +01:00
attrs.append('sum="Debit"')
2008-03-17 18:32:06 +01:00
elif column.field.name == 'credit':
2008-03-18 17:30:54 +01:00
attrs.append('sum="Credit"')
2008-03-17 18:32:06 +01:00
if column.readonly:
attrs.append('readonly="1"')
if column.required:
attrs.append('required="1"')
else:
attrs.append('required="0"')
2012-04-03 20:06:15 +02:00
xml += ('<field name="%s" %s/>\n'
% (column.field.name, ' '.join(attrs)))
2012-09-24 22:17:29 +02:00
for depend in getattr(cls, column.field.name).depends:
fields.add(depend)
fields.add('state')
2008-03-17 18:32:06 +01:00
xml += '</tree>'
result['arch'] = xml
2012-09-24 22:17:29 +02:00
result['fields'] = cls.fields_get(fields_names=list(fields))
2008-03-17 18:32:06 +01:00
return result
2012-09-24 22:17:29 +02:00
@classmethod
2013-11-28 23:26:15 +01:00
def reconcile(cls, lines, journal=None, date=None, account=None,
description=None):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Move = pool.get('account.move')
Reconciliation = pool.get('account.move.reconciliation')
Period = pool.get('account.period')
Date = pool.get('ir.date')
2012-09-24 22:17:29 +02:00
for line in lines:
2008-11-13 10:48:40 +01:00
if line.reconciliation:
2012-09-24 22:17:29 +02:00
cls.raise_user_error('already_reconciled',
2013-02-03 15:06:55 -03:00
error_args=(line.move.number, line.id,))
2008-11-13 10:48:40 +01:00
2012-09-24 22:17:29 +02:00
lines = lines[:]
2013-12-20 13:59:46 +01:00
reconcile_account = None
amount = Decimal('0.0')
for line in lines:
amount += line.debit - line.credit
if not reconcile_account:
reconcile_account = line.account
amount = reconcile_account.currency.round(amount)
if not account and journal:
if amount >= 0:
account = journal.debit_account
else:
account = journal.credit_account
2012-09-24 22:17:29 +02:00
if journal and account:
if not date:
2012-09-24 22:17:29 +02:00
date = Date.today()
2013-01-26 15:11:34 +01:00
period_id = Period.find(reconcile_account.company.id, date=date)
2013-01-06 22:18:13 +01:00
move, = Move.create([{
'journal': journal.id,
'period': period_id,
'date': date,
2013-11-28 23:26:15 +01:00
'description': description,
2013-01-06 22:18:13 +01:00
'lines': [
('create', [{
2013-01-26 15:11:34 +01:00
'account': reconcile_account.id,
2013-02-16 18:54:35 +01:00
'debit': (amount < Decimal('0.0')
2013-01-06 22:18:13 +01:00
and - amount or Decimal('0.0')),
2013-02-16 18:54:35 +01:00
'credit': (amount > Decimal('0.0')
2013-01-06 22:18:13 +01:00
and amount or Decimal('0.0')),
}, {
'account': account.id,
2013-02-16 18:54:35 +01:00
'debit': (amount > Decimal('0.0')
2013-01-06 22:18:13 +01:00
and amount or Decimal('0.0')),
2013-02-16 18:54:35 +01:00
'credit': (amount < Decimal('0.0')
2013-01-06 22:18:13 +01:00
and - amount or Decimal('0.0')),
}]),
],
}])
2012-09-24 22:17:29 +02:00
lines += cls.search([
2013-02-16 18:54:35 +01:00
('move', '=', move.id),
('account', '=', reconcile_account.id),
('debit', '=', amount < Decimal('0.0') and - amount
or Decimal('0.0')),
2013-02-16 18:54:35 +01:00
('credit', '=', amount > Decimal('0.0') and amount
or Decimal('0.0')),
2013-02-16 18:54:35 +01:00
], limit=1)
2013-01-06 22:18:13 +01:00
return Reconciliation.create([{
'lines': [('add', [x.id for x in lines])],
}])[0]
2008-03-17 18:32:06 +01:00
2009-02-28 16:57:10 +01:00
class OpenJournalAsk(ModelView):
'Open Journal Ask'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.open_journal.ask'
2008-03-17 18:32:06 +01:00
journal = fields.Many2One('account.journal', 'Journal', required=True)
period = fields.Many2One('account.period', 'Period', required=True,
2011-08-21 11:20:29 +02:00
domain=[
('state', '!=', 'close'),
('fiscalyear.company.id', '=',
Eval('context', {}).get('company', 0)),
2010-01-20 10:56:33 +01:00
])
2008-03-17 18:32:06 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_period():
Period = Pool().get('account.period')
return Period.find(Transaction().context.get('company'),
2010-08-19 22:02:00 +02:00
exception=False)
2008-03-17 18:32:06 +01:00
class OpenJournal(Wizard):
'Open Journal'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.open_journal'
2012-01-02 17:54:33 +01:00
start = StateTransition()
ask = StateView('account.move.open_journal.ask',
'account.open_journal_ask_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('account.act_move_line_form')
2012-09-24 22:17:29 +02:00
def transition_start(self):
2012-04-03 20:06:15 +02:00
if (Transaction().context.get('active_model', '')
== 'account.journal.period'
2012-01-02 17:54:33 +01:00
and Transaction().context.get('active_id')):
return 'open_'
return 'ask'
2012-09-24 22:17:29 +02:00
def default_ask(self, fields):
JournalPeriod = Pool().get('account.journal.period')
2012-01-02 17:54:33 +01:00
if (Transaction().context.get('active_model', '') ==
'account.journal.period'
and Transaction().context.get('active_id')):
2012-09-24 22:17:29 +02:00
journal_period = JournalPeriod(Transaction().context['active_id'])
return {
'journal': journal_period.journal.id,
'period': journal_period.period.id,
2012-09-24 22:17:29 +02:00
}
return {}
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
JournalPeriod = Pool().get('account.journal.period')
2012-01-02 17:54:33 +01:00
if (Transaction().context.get('active_model', '') ==
'account.journal.period'
and Transaction().context.get('active_id')):
2012-09-24 22:17:29 +02:00
journal_period = JournalPeriod(Transaction().context['active_id'])
journal = journal_period.journal
period = journal_period.period
else:
2012-09-24 22:17:29 +02:00
journal = self.ask.journal
period = self.ask.period
journal_periods = JournalPeriod.search([
('journal', '=', journal.id),
('period', '=', period.id),
], limit=1)
if not journal_periods:
2013-01-06 22:18:13 +01:00
journal_period, = JournalPeriod.create([{
'name': journal.name + ' - ' + period.name,
'journal': journal.id,
'period': period.id,
}])
2012-01-02 17:54:33 +01:00
else:
2012-09-24 22:17:29 +02:00
journal_period, = journal_periods
2012-01-02 17:54:33 +01:00
action['name'] += ' - %s' % journal_period.rec_name
action['pyson_domain'] = PYSONEncoder().encode([
2012-09-24 22:17:29 +02:00
('journal', '=', journal.id),
('period', '=', period.id),
2012-01-02 17:54:33 +01:00
])
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:17:29 +02:00
'journal': journal.id,
'period': period.id,
2008-07-29 12:14:16 +02:00
})
2012-01-02 17:54:33 +01:00
return action, {}
2012-09-24 22:17:29 +02:00
def transition_open_(self):
2012-01-02 17:54:33 +01:00
return 'end'
2008-03-17 18:32:06 +01:00
2008-03-18 13:20:12 +01:00
class OpenAccount(Wizard):
'Open Account'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.open_account'
2012-01-02 17:54:33 +01:00
start_state = 'open_'
open_ = StateAction('account.act_move_line_form')
2008-03-18 13:20:12 +01:00
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
FiscalYear = Pool().get('account.fiscalyear')
2008-03-18 13:20:12 +01:00
2010-08-19 22:02:00 +02:00
if not Transaction().context.get('fiscalyear'):
2012-09-24 22:17:29 +02:00
fiscalyears = FiscalYear.search([
('state', '=', 'open'),
])
2008-03-18 13:20:12 +01:00
else:
2012-09-24 22:17:29 +02:00
fiscalyears = [FiscalYear(Transaction().context['fiscalyear'])]
2008-03-18 13:20:12 +01:00
2012-09-24 22:17:29 +02:00
periods = [p for f in fiscalyears for p in f.periods]
2008-03-18 13:20:12 +01:00
2012-01-02 17:54:33 +01:00
action['pyson_domain'] = [
2012-09-24 22:17:29 +02:00
('period', 'in', [p.id for p in periods]),
2012-01-02 17:54:33 +01:00
('account', '=', Transaction().context['active_id']),
2008-03-28 17:39:54 +01:00
]
2010-08-19 22:02:00 +02:00
if Transaction().context.get('posted'):
2012-01-02 17:54:33 +01:00
action['pyson_domain'].append(('move.state', '=', 'posted'))
2012-08-16 15:55:45 +02:00
if Transaction().context.get('date'):
action['pyson_domain'].append(('move.date', '<=',
Transaction().context['date']))
2012-01-02 17:54:33 +01:00
action['pyson_domain'] = PYSONEncoder().encode(action['pyson_domain'])
action['pyson_context'] = PYSONEncoder().encode({
2010-08-19 22:02:00 +02:00
'fiscalyear': Transaction().context.get('fiscalyear'),
2010-01-20 10:56:33 +01:00
})
2012-01-02 17:54:33 +01:00
return action, {}
2008-03-18 13:20:12 +01:00
2008-03-18 23:40:57 +01:00
2009-02-28 16:57:10 +01:00
class ReconcileLinesWriteOff(ModelView):
2008-03-19 22:13:51 +01:00
'Reconcile Lines Write-Off'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.reconcile_lines.writeoff'
2013-12-20 13:59:46 +01:00
journal = fields.Many2One('account.journal', 'Journal', required=True,
domain=[
('type', '=', 'write-off'),
])
date = fields.Date('Date', required=True)
2013-08-21 18:19:26 +02:00
amount = fields.Numeric('Amount', digits=(16, Eval('currency_digits', 2)),
readonly=True, depends=['currency_digits'])
currency_digits = fields.Integer('Currency Digits', readonly=True)
2013-11-28 23:26:15 +01:00
description = fields.Char('Description')
2008-03-19 22:13:51 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_date():
Date = Pool().get('ir.date')
return Date.today()
2008-03-19 22:13:51 +01:00
class ReconcileLines(Wizard):
'Reconcile Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.reconcile_lines'
2012-01-02 17:54:33 +01:00
start = StateTransition()
writeoff = StateView('account.move.reconcile_lines.writeoff',
'account.reconcile_lines_writeoff_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Reconcile', 'reconcile', 'tryton-ok', default=True),
])
reconcile = StateTransition()
2013-08-21 18:19:26 +02:00
def get_writeoff(self):
"Return writeoff amount and company"
2012-09-24 22:17:29 +02:00
Line = Pool().get('account.move.line')
2008-03-19 22:13:51 +01:00
company = None
amount = Decimal('0.0')
2012-09-24 22:17:29 +02:00
for line in Line.browse(Transaction().context['active_ids']):
2008-03-19 22:13:51 +01:00
amount += line.debit - line.credit
if not company:
company = line.account.company
2013-08-21 18:19:26 +02:00
return amount, company
def transition_start(self):
amount, company = self.get_writeoff()
if not company:
return 'end'
2012-09-24 22:17:29 +02:00
if company.currency.is_zero(amount):
2008-03-19 22:13:51 +01:00
return 'reconcile'
return 'writeoff'
2013-08-21 18:19:26 +02:00
def default_writeoff(self, fields):
amount, company = self.get_writeoff()
return {
'amount': amount,
'currency_digits': company.currency.digits,
}
2012-09-24 22:17:29 +02:00
def transition_reconcile(self):
Line = Pool().get('account.move.line')
2008-03-19 22:13:51 +01:00
2013-01-26 15:11:34 +01:00
journal = getattr(self.writeoff, 'journal', None)
date = getattr(self.writeoff, 'date', None)
2013-11-28 23:26:15 +01:00
description = getattr(self.writeoff, 'description', None)
2012-09-24 22:17:29 +02:00
Line.reconcile(Line.browse(Transaction().context['active_ids']),
2013-12-20 13:59:46 +01:00
journal=journal, date=date, description=description)
2012-01-02 17:54:33 +01:00
return 'end'
2008-03-19 22:13:51 +01:00
2012-01-02 17:54:33 +01:00
class UnreconcileLinesStart(ModelView):
'Unreconcile Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.unreconcile_lines.start'
class UnreconcileLines(Wizard):
'Unreconcile Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.unreconcile_lines'
2012-03-25 00:17:23 +01:00
start_state = 'unreconcile'
2012-01-02 17:54:33 +01:00
unreconcile = StateTransition()
2012-09-24 22:17:29 +02:00
def transition_unreconcile(self):
pool = Pool()
Line = pool.get('account.move.line')
Reconciliation = pool.get('account.move.reconciliation')
2012-09-24 22:17:29 +02:00
lines = Line.browse(Transaction().context['active_ids'])
reconciliations = [x.reconciliation for x in lines if x.reconciliation]
if reconciliations:
Reconciliation.delete(reconciliations)
2012-01-02 17:54:33 +01:00
return 'end'
2012-01-02 17:54:33 +01:00
class OpenReconcileLinesStart(ModelView):
'Open Reconcile Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.open_reconcile_lines.start'
2008-03-19 22:13:51 +01:00
account = fields.Many2One('account.account', 'Account', required=True,
domain=[('kind', '!=', 'view'), ('reconcile', '=', True)])
2008-03-19 22:13:51 +01:00
class OpenReconcileLines(Wizard):
'Open Reconcile Lines'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.open_reconcile_lines'
2012-01-02 17:54:33 +01:00
start = StateView('account.move.open_reconcile_lines.start',
'account.open_reconcile_lines_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('account.act_move_line_form')
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
2013-07-22 14:51:43 +02:00
encoder = PYSONEncoder()
action['pyson_domain'] = encoder.encode([
2012-09-24 22:17:29 +02:00
('account', '=', self.start.account.id),
2012-03-27 10:43:03 +02:00
('reconciliation', '=', None),
2008-03-19 22:13:51 +01:00
])
2013-07-22 14:51:43 +02:00
if self.start.account.kind == 'receivable':
order = [('credit', 'DESC'), ('id', 'DESC')]
elif self.start.account.kind == 'payable':
order = [('debit', 'DESC'), ('id', 'DESC')]
else:
order = None
action['pyson_order'] = encoder.encode(order)
2012-01-02 17:54:33 +01:00
return action, {}
2008-03-19 22:13:51 +01:00
2009-03-05 14:51:19 +01:00
class FiscalYearLine(ModelSQL):
2009-03-17 13:09:06 +01:00
'Fiscal Year - Move Line'
2012-09-24 22:17:29 +02:00
__name__ = 'account.fiscalyear-account.move.line'
2009-03-05 14:51:19 +01:00
_table = 'account_fiscalyear_line_rel'
2009-03-17 13:09:06 +01:00
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2012-03-05 10:52:56 +01:00
ondelete='CASCADE', select=True)
2009-03-05 14:51:19 +01:00
line = fields.Many2One('account.move.line', 'Line', ondelete='RESTRICT',
2012-03-05 10:52:56 +01:00
select=True, required=True)
2009-03-05 14:51:19 +01:00
2012-09-24 22:17:29 +02:00
class FiscalYear2:
__name__ = 'account.fiscalyear'
2009-03-05 14:51:19 +01:00
close_lines = fields.Many2Many('account.fiscalyear-account.move.line',
'fiscalyear', 'line', 'Close Lines')
2012-01-02 17:54:33 +01:00
class PrintGeneralJournalStart(ModelView):
'Print General Journal'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.print_general_journal.start'
2008-03-30 17:03:45 +02:00
from_date = fields.Date('From Date', required=True)
to_date = fields.Date('To Date', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
2009-03-20 13:49:25 +01:00
posted = fields.Boolean('Posted Move', help='Show only posted move')
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_from_date():
Date = Pool().get('ir.date')
return datetime.date(Date.today().year, 1, 1)
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_to_date():
Date = Pool().get('ir.date')
return Date.today()
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_company():
2012-03-27 10:43:03 +02:00
return Transaction().context.get('company')
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
2008-03-30 17:03:45 +02:00
return False
class PrintGeneralJournal(Wizard):
'Print General Journal'
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.print_general_journal'
2012-01-02 17:54:33 +01:00
start = StateView('account.move.print_general_journal.start',
'account.print_general_journal_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateAction('account.report_general_journal')
2012-09-24 22:17:29 +02:00
def do_print_(self, action):
2012-01-02 17:54:33 +01:00
data = {
2012-09-24 22:17:29 +02:00
'company': self.start.company.id,
'from_date': self.start.from_date,
'to_date': self.start.to_date,
'posted': self.start.posted,
2012-01-02 17:54:33 +01:00
}
return action, data
2008-03-30 17:03:45 +02:00
class GeneralJournal(Report):
2012-09-24 22:17:29 +02:00
__name__ = 'account.move.general_journal'
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def _get_records(cls, ids, model, data):
Move = Pool().get('account.move')
2008-03-30 17:03:45 +02:00
clause = [
2012-01-02 17:54:33 +01:00
('date', '>=', data['from_date']),
('date', '<=', data['to_date']),
('period.fiscalyear.company', '=', data['company']),
]
2012-01-02 17:54:33 +01:00
if data['posted']:
clause.append(('state', '=', 'posted'))
2012-09-24 22:17:29 +02:00
return Move.search(clause,
2012-09-29 15:33:21 +02:00
order=[('date', 'ASC'), ('id', 'ASC')])
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def parse(cls, report, moves, data, localcontext):
Company = Pool().get('company.company')
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
company = Company(data['company'])
2008-03-30 17:03:45 +02:00
2010-08-19 22:02:00 +02:00
localcontext['company'] = company
localcontext['digits'] = company.currency.digits
2012-01-02 17:54:33 +01:00
localcontext['from_date'] = data['from_date']
localcontext['to_date'] = data['to_date']
2008-03-30 17:03:45 +02:00
2012-09-24 22:17:29 +02:00
return super(GeneralJournal, cls).parse(report, moves, data,
2012-01-02 17:54:33 +01:00
localcontext)