Files
tryton/account.py
T

2191 lines
79 KiB
Python
Raw Normal View History

2014-12-02 12:54:29 +01: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.
2010-08-19 22:02:00 +02:00
from decimal import Decimal
import datetime
import operator
2013-09-17 10:49:25 +02:00
from itertools import izip, groupby
from sql import Column, Literal, Null
2013-09-06 22:33:47 +02:00
from sql.aggregate import Sum
from sql.conditionals import Coalesce
2009-02-28 16:57:10 +01:00
from trytond.model import ModelView, ModelSQL, fields
2012-04-03 20:06:15 +02:00
from trytond.wizard import Wizard, StateView, StateAction, StateTransition, \
Button
2008-03-28 17:25:14 +01:00
from trytond.report import Report
2014-07-17 18:56:39 +02:00
from trytond.tools import reduce_ids, grouped_slice
2011-08-21 11:20:29 +02:00
from trytond.pyson import Eval, PYSONEncoder, Date
2010-08-19 22:02:00 +02:00
from trytond.transaction import Transaction
2011-07-03 13:18:40 +02:00
from trytond.pool import Pool
2013-09-06 22:33:47 +02:00
from trytond import backend
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
__all__ = ['TypeTemplate', 'Type', 'OpenType', 'AccountTemplate', 'Account',
'AccountDeferral', 'OpenChartAccountStart', 'OpenChartAccount',
2012-10-17 23:54:35 +02:00
'PrintGeneralLedgerStart', 'PrintGeneralLedger', 'GeneralLedger',
2012-09-24 22:17:29 +02:00
'PrintTrialBalanceStart', 'PrintTrialBalance', 'TrialBalance',
'OpenBalanceSheetStart', 'OpenBalanceSheet',
'OpenIncomeStatementStart', 'OpenIncomeStatement',
'CreateChartStart', 'CreateChartAccount', 'CreateChartProperties',
'CreateChart', 'UpdateChartStart', 'UpdateChartSucceed', 'UpdateChart',
'OpenThirdPartyBalanceStart', 'OpenThirdPartyBalance', 'ThirdPartyBalance',
'OpenAgedBalanceStart', 'OpenAgedBalance', 'AgedBalance']
2008-03-13 23:22:59 +01:00
2009-02-28 16:57:10 +01:00
class TypeTemplate(ModelSQL, ModelView):
2008-08-28 12:39:04 +02:00
'Account Type Template'
2012-09-24 22:17:29 +02:00
__name__ = 'account.account.type.template'
2008-08-28 12:39:04 +02:00
name = fields.Char('Name', required=True, translate=True)
parent = fields.Many2One('account.account.type.template', 'Parent',
2009-04-07 18:21:24 +02:00
ondelete="RESTRICT")
2012-04-03 20:06:15 +02:00
childs = fields.One2Many('account.account.type.template', 'parent',
'Children')
2013-09-06 22:33:47 +02:00
sequence = fields.Integer('Sequence')
2008-08-28 12:39:04 +02:00
balance_sheet = fields.Boolean('Balance Sheet')
income_statement = fields.Boolean('Income Statement')
display_balance = fields.Selection([
('debit-credit', 'Debit - Credit'),
('credit-debit', 'Credit - Debit'),
], 'Display Balance', required=True)
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(TypeTemplate, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
2008-08-28 12:39:04 +02: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-05-14 15:36:13 +02:00
cursor = Transaction().cursor
2012-09-24 22:17:29 +02:00
table = TableHandler(cursor, cls, module_name)
2012-05-14 15:36:13 +02:00
2012-09-24 22:17:29 +02:00
super(TypeTemplate, cls).__register__(module_name)
2012-05-14 15:36:13 +02:00
# 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')
2013-09-06 22:33:47 +02:00
@staticmethod
def order_sequence(tables):
table, _ = tables[None]
return [table.sequence == Null, table.sequence]
2013-09-06 22:33:47 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_balance_sheet():
2008-08-28 12:39:04 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_income_statement():
2008-08-28 12:39:04 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_display_balance():
2008-08-28 12:39:04 +02:00
return 'debit-credit'
2012-09-24 22:17:29 +02:00
def get_rec_name(self, name):
if self.parent:
return self.parent.get_rec_name(name) + '\\' + self.name
else:
return self.name
2012-04-03 20:06:15 +02:00
2012-09-24 22:17:29 +02:00
def _get_type_value(self, type=None):
2008-08-28 12:39:04 +02:00
'''
Set the values for account creation.
'''
res = {}
2012-09-24 22:17:29 +02:00
if not type or type.name != self.name:
res['name'] = self.name
if not type or type.sequence != self.sequence:
res['sequence'] = self.sequence
if not type or type.balance_sheet != self.balance_sheet:
res['balance_sheet'] = self.balance_sheet
if not type or type.income_statement != self.income_statement:
res['income_statement'] = self.income_statement
if not type or type.display_balance != self.display_balance:
res['display_balance'] = self.display_balance
2012-10-21 21:11:39 +02:00
if not type or type.template != self:
2012-09-24 22:17:29 +02:00
res['template'] = self.id
2008-08-28 12:39:04 +02:00
return res
2012-09-24 22:17:29 +02:00
def create_type(self, company_id, template2type=None, parent_id=None):
2008-08-28 12:39:04 +02:00
'''
Create recursively types based on template.
2012-09-24 22:17:29 +02:00
template2type is a dictionary with template id as key and type id as
value, used to convert template id into type. The dictionary is filled
with new types.
Return the id of the type created
2008-08-28 12:39:04 +02:00
'''
2012-09-24 22:17:29 +02:00
pool = Pool()
Type = pool.get('account.account.type')
Lang = pool.get('ir.lang')
2012-11-23 18:00:16 +01:00
Config = pool.get('ir.configuration')
2008-08-28 12:39:04 +02:00
if template2type is None:
template2type = {}
2012-09-24 22:17:29 +02:00
if self.id not in template2type:
vals = self._get_type_value()
2008-08-28 12:39:04 +02:00
vals['company'] = company_id
vals['parent'] = parent_id
2013-01-06 22:18:13 +01:00
new_type, = Type.create([vals])
2012-11-23 18:00:16 +01:00
prev_lang = self._context.get('language') or Config.get_language()
prev_data = {}
2012-09-24 22:17:29 +02:00
for field_name, field in self._fields.iteritems():
if getattr(field, 'translate', False):
2012-09-24 22:17:29 +02:00
prev_data[field_name] = getattr(self, field_name)
for lang in Lang.get_translatable_languages():
if lang == prev_lang:
continue
2012-09-24 22:17:29 +02:00
with Transaction().set_context(language=lang):
template = self.__class__(self.id)
data = {}
for field_name, field in template._fields.iteritems():
if (getattr(field, 'translate', False)
and (getattr(template, field_name) !=
prev_data[field_name])):
data[field_name] = getattr(template, field_name)
if data:
Type.write([new_type], data)
template2type[self.id] = new_type.id
new_id = template2type[self.id]
2008-08-28 12:39:04 +02:00
new_childs = []
2012-09-24 22:17:29 +02:00
for child in self.childs:
new_childs.append(child.create_type(company_id,
2010-08-19 22:02:00 +02:00
template2type=template2type, parent_id=new_id))
2008-08-28 12:39:04 +02:00
return new_id
2009-02-28 16:57:10 +01:00
class Type(ModelSQL, ModelView):
2008-03-13 23:22:59 +01:00
'Account Type'
2012-09-24 22:17:29 +02:00
__name__ = 'account.account.type'
2008-03-13 23:22:59 +01:00
name = fields.Char('Name', size=None, required=True, translate=True)
2008-08-28 12:39:04 +02:00
parent = fields.Many2One('account.account.type', 'Parent',
2011-08-04 16:57:14 +02:00
ondelete="RESTRICT", domain=[
2012-01-02 18:51:05 +01:00
('company', '=', Eval('company')),
], depends=['company'])
2011-04-11 11:34:51 +02:00
childs = fields.One2Many('account.account.type', 'parent', 'Children',
domain=[
('company', '=', Eval('company')),
], depends=['company'])
2012-05-14 15:36:13 +02:00
sequence = fields.Integer('Sequence',
help='Use to order the account type')
2010-03-11 16:45:27 +01:00
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'get_currency_digits')
amount = fields.Function(fields.Numeric('Amount',
digits=(16, Eval('currency_digits', 2)), depends=['currency_digits']),
'get_amount')
2008-08-28 12:39:04 +02:00
balance_sheet = fields.Boolean('Balance Sheet')
2008-08-13 10:17:29 +02:00
income_statement = fields.Boolean('Income Statement')
2008-05-23 12:32:10 +02:00
display_balance = fields.Selection([
('debit-credit', 'Debit - Credit'),
('credit-debit', 'Credit - Debit'),
], 'Display Balance', required=True)
2008-08-28 12:39:04 +02:00
company = fields.Many2One('company.company', 'Company', required=True,
2009-04-07 18:21:24 +02:00
ondelete="RESTRICT")
template = fields.Many2One('account.account.type.template', 'Template')
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(Type, cls).__setup__()
cls._order.insert(0, ('sequence', 'ASC'))
2008-04-22 17:47:52 +02: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-05-14 15:36:13 +02:00
cursor = Transaction().cursor
2012-09-24 22:17:29 +02:00
table = TableHandler(cursor, cls, module_name)
2012-05-14 15:36:13 +02:00
2012-09-24 22:17:29 +02:00
super(Type, cls).__register__(module_name)
2012-05-14 15:36:13 +02:00
# 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')
2013-09-06 22:33:47 +02:00
@staticmethod
def order_sequence(tables):
table, _ = tables[None]
return [table.sequence == Null, table.sequence]
2013-09-06 22:33:47 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_balance_sheet():
2008-04-16 18:22:03 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_income_statement():
2008-04-16 18:22:03 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_display_balance():
2008-05-23 12:32:10 +02:00
return 'debit-credit'
2012-09-24 22:17:29 +02:00
def get_currency_digits(self, name):
return self.company.currency.digits
2008-07-29 11:40:24 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def get_amount(cls, types, name):
pool = Pool()
Account = pool.get('account.account')
res = {}
2012-09-24 22:17:29 +02:00
for type_ in types:
res[type_.id] = Decimal('0.0')
2012-09-24 22:17:29 +02:00
childs = cls.search([
('parent', 'child_of', [t.id for t in types]),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
type_sum = {}
for type_ in childs:
type_sum[type_.id] = Decimal('0.0')
accounts = Account.search([
('type', 'in', [t.id for t in childs]),
2013-09-12 18:57:18 +02:00
('kind', '!=', 'view'),
2012-09-24 22:17:29 +02:00
])
for account in accounts:
2013-09-12 18:57:18 +02:00
type_sum[account.type.id] += (account.debit - account.credit)
2012-09-24 22:17:29 +02:00
for type_ in types:
childs = cls.search([
('parent', 'child_of', [type_.id]),
])
for child in childs:
res[type_.id] += type_sum[child.id]
res[type_.id] = type_.company.currency.round(res[type_.id])
if type_.display_balance == 'credit-debit':
res[type_.id] = - res[type_.id]
return res
2012-09-24 22:17:29 +02:00
def get_rec_name(self, name):
if self.parent:
return self.parent.get_rec_name(name) + '\\' + self.name
else:
return self.name
2012-04-03 20:06:15 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def delete(cls, types):
types = cls.search([
('parent', 'child_of', [t.id for t in types]),
])
super(Type, cls).delete(types)
2008-05-23 12:40:43 +02:00
2012-09-24 22:17:29 +02:00
def update_type(self, template2type=None):
'''
Update recursively types based on template.
2012-09-24 22:17:29 +02:00
template2type is a dictionary with template id as key and type id as
value, used to convert template id into type. The dictionary is filled
with new types
'''
2012-11-23 18:00:16 +01:00
pool = Pool()
Lang = pool.get('ir.lang')
Config = pool.get('ir.configuration')
if template2type is None:
template2type = {}
2012-09-24 22:17:29 +02:00
if self.template:
vals = self.template._get_type_value(type=self)
if vals:
2012-09-24 22:17:29 +02:00
self.write([self], vals)
2012-11-23 18:00:16 +01:00
prev_lang = self._context.get('language') or Config.get_language()
prev_data = {}
2012-09-24 22:17:29 +02:00
for field_name, field in self.template._fields.iteritems():
if getattr(field, 'translate', False):
2012-09-24 22:17:29 +02:00
prev_data[field_name] = getattr(self.template, field_name)
for lang in Lang.get_translatable_languages():
if lang == prev_lang:
continue
2012-09-24 22:17:29 +02:00
with Transaction().set_context(language=lang):
type_ = self.__class__(self.id)
data = {}
for field_name, field in (
type_.template._fields.iteritems()):
if (getattr(field, 'translate', False)
and (getattr(type_.template, field_name) !=
prev_data[field_name])):
data[field_name] = getattr(type_.template,
field_name)
if data:
self.write([type_], data)
template2type[self.template.id] = self.id
2012-09-24 22:17:29 +02:00
for child in self.childs:
child.update_type(template2type=template2type)
2008-03-13 23:22:59 +01:00
2012-08-16 15:55:45 +02:00
class OpenType(Wizard):
'Open Type'
2012-09-24 22:17:29 +02:00
__name__ = 'account.account.open_type'
2012-08-16 15:55:45 +02:00
start_state = 'open_'
open_ = StateAction('account.act_account_list2')
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
2012-08-16 15:55:45 +02:00
action['pyson_domain'] = PYSONEncoder().encode([
('type', '=', Transaction().context['active_id']),
2013-09-12 18:57:18 +02:00
('kind', '!=', 'view'),
2012-08-16 15:55:45 +02:00
])
action['pyson_context'] = PYSONEncoder().encode({
'date': Transaction().context.get('date'),
'posted': Transaction().context.get('posted'),
2013-09-12 18:57:18 +02:00
'cumulate': Transaction().context.get('cumulate'),
2012-08-16 15:55:45 +02:00
})
return action, {}
2009-02-28 16:57:10 +01:00
class AccountTemplate(ModelSQL, ModelView):
'Account Template'
2012-09-24 22:17:29 +02:00
__name__ = 'account.account.template'
name = fields.Char('Name', size=None, required=True, translate=True,
2012-03-05 10:52:56 +01:00
select=True)
code = fields.Char('Code', size=None, select=True)
2008-08-28 12:39:04 +02:00
type = fields.Many2One('account.account.type.template', 'Type',
2011-08-21 11:20:29 +02:00
ondelete="RESTRICT",
states={
'invisible': Eval('kind') == 'view',
'required': Eval('kind') != 'view',
}, depends=['kind'])
2012-03-05 10:52:56 +01:00
parent = fields.Many2One('account.account.template', 'Parent', select=True,
2009-04-07 18:21:24 +02:00
ondelete="RESTRICT")
2009-03-19 19:29:19 +01:00
childs = fields.One2Many('account.account.template', 'parent', 'Children')
reconcile = fields.Boolean('Reconcile',
2011-08-21 11:20:29 +02:00
states={
'invisible': Eval('kind') == 'view',
}, depends=['kind'])
kind = fields.Selection([
2012-03-30 14:18:10 +02:00
('other', 'Other'),
('payable', 'Payable'),
('revenue', 'Revenue'),
('receivable', 'Receivable'),
('expense', 'Expense'),
('stock', 'Stock'),
('view', 'View'),
], 'Kind', required=True)
2008-09-19 15:00:26 +02:00
deferral = fields.Boolean('Deferral', states={
2011-08-21 11:20:29 +02:00
'invisible': Eval('kind') == 'view',
}, depends=['kind'])
party_required = fields.Boolean('Party Required',
states={
'invisible': Eval('kind') == 'view',
},
depends=['kind'])
general_ledger_balance = fields.Boolean('General Ledger Balance',
states={
'invisible': Eval('kind') == 'view',
},
depends=['kind'],
help="Display only the balance in the general ledger report")
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(AccountTemplate, cls).__setup__()
cls._order.insert(0, ('code', 'ASC'))
cls._order.insert(1, ('name', 'ASC'))
2008-04-22 17:47:52 +02:00
@classmethod
def validate(cls, templates):
super(AccountTemplate, cls).validate(templates)
cls.check_recursion(templates)
2012-09-24 22:17:29 +02:00
@staticmethod
def default_kind():
return 'view'
2012-09-24 22:17:29 +02:00
@staticmethod
def default_reconcile():
2008-07-29 21:18:31 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_deferral():
2008-09-19 15:00:26 +02:00
return True
@staticmethod
def default_party_required():
return False
@staticmethod
def default_general_ledger_balance():
return False
2012-09-24 22:17:29 +02:00
def get_rec_name(self, name):
if self.code:
return self.code + ' - ' + self.name
else:
return self.name
2008-05-14 17:39:01 +02: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',
('code',) + tuple(clause[1:]),
(cls._rec_name,) + tuple(clause[1:]),
]
2008-05-14 17:39:01 +02:00
2012-09-24 22:17:29 +02:00
def _get_account_value(self, account=None):
2008-07-21 13:59:50 +02:00
'''
Set the values for account creation.
'''
res = {}
2012-09-24 22:17:29 +02:00
if not account or account.name != self.name:
res['name'] = self.name
if not account or account.code != self.code:
res['code'] = self.code
if not account or account.kind != self.kind:
res['kind'] = self.kind
if not account or account.reconcile != self.reconcile:
res['reconcile'] = self.reconcile
if not account or account.deferral != self.deferral:
res['deferral'] = self.deferral
if not account or account.party_required != self.party_required:
res['party_required'] = self.party_required
if (not account
or account.general_ledger_balance !=
self.general_ledger_balance):
res['general_ledger_balance'] = self.general_ledger_balance
2012-10-21 21:11:39 +02:00
if not account or account.template != self:
2012-09-24 22:17:29 +02:00
res['template'] = self.id
return res
2012-09-24 22:17:29 +02:00
def create_account(self, company_id, template2account=None,
2012-03-27 10:43:03 +02:00
template2type=None, parent_id=None):
2008-07-21 13:59:50 +02:00
'''
Create recursively accounts based on template.
2012-09-24 22:17:29 +02:00
template2account is a dictionary with template id as key and account id
as value, used to convert template id into account. The dictionary is
filled with new accounts
template2type is a dictionary with type template id as key and type id
as value, used to convert type template id into type.
Return the id of the account created
2008-07-21 13:59:50 +02:00
'''
2012-09-24 22:17:29 +02:00
pool = Pool()
Account = pool.get('account.account')
Lang = pool.get('ir.lang')
2012-11-23 18:00:16 +01:00
Config = pool.get('ir.configuration')
if template2account is None:
template2account = {}
2008-08-28 12:39:04 +02:00
if template2type is None:
template2type = {}
2012-09-24 22:17:29 +02:00
if self.id not in template2account:
vals = self._get_account_value()
vals['company'] = company_id
vals['parent'] = parent_id
2012-10-17 12:33:30 +02:00
vals['type'] = (template2type.get(self.type.id) if self.type
else None)
2013-01-06 22:18:13 +01:00
new_account, = Account.create([vals])
2012-11-23 18:00:16 +01:00
prev_lang = self._context.get('language') or Config.get_language()
prev_data = {}
2012-09-24 22:17:29 +02:00
for field_name, field in self._fields.iteritems():
if getattr(field, 'translate', False):
2012-09-24 22:17:29 +02:00
prev_data[field_name] = getattr(self, field_name)
for lang in Lang.get_translatable_languages():
if lang == prev_lang:
continue
2012-09-24 22:17:29 +02:00
with Transaction().set_context(language=lang):
template = self.__class__(self.id)
data = {}
for field_name, field in self._fields.iteritems():
2013-02-16 18:54:35 +01:00
if (getattr(field, 'translate', False)
2012-09-24 22:17:29 +02:00
and (getattr(template, field_name) !=
prev_data[field_name])):
data[field_name] = getattr(template, field_name)
if data:
Account.write([new_account], data)
template2account[self.id] = new_account.id
new_id = template2account[self.id]
new_childs = []
2012-09-24 22:17:29 +02:00
for child in self.childs:
new_childs.append(child.create_account(company_id,
2010-08-19 22:02:00 +02:00
template2account=template2account, template2type=template2type,
parent_id=new_id))
return new_id
2012-09-24 22:17:29 +02:00
def update_account_taxes(self, template2account, template2tax,
2010-08-19 22:02:00 +02:00
template_done=None):
'''
Update recursively account taxes based on template.
2012-09-24 22:17:29 +02:00
template2account is a dictionary with template id as key and account id
as value, used to convert template id into account.
template2tax is a dictionary with tax template id as key and tax id as
value, used to convert tax template id into tax.
template_done is a list of template id already updated. The list is
filled.
'''
2012-09-24 22:17:29 +02:00
Account = Pool().get('account.account')
if template2account is None:
template2account = {}
if template2tax is None:
template2tax = {}
if template_done is None:
template_done = []
2012-09-24 22:17:29 +02:00
if self.id not in template_done:
if self.taxes:
Account.write([Account(template2account[self.id])], {
'taxes': [
2014-04-16 10:12:37 +00:00
('add', [template2tax[x.id] for x in self.taxes])],
2012-09-24 22:17:29 +02:00
})
template_done.append(self.id)
2012-09-24 22:17:29 +02:00
for child in self.childs:
child.update_account_taxes(template2account, template2tax,
template_done=template_done)
2009-02-28 16:57:10 +01:00
class Account(ModelSQL, ModelView):
2008-03-13 23:22:59 +01:00
'Account'
2012-09-24 22:17:29 +02:00
__name__ = 'account.account'
2008-03-13 23:22:59 +01:00
name = fields.Char('Name', size=None, required=True, translate=True,
2012-03-05 10:52:56 +01:00
select=True)
code = fields.Char('Code', size=None, select=True)
active = fields.Boolean('Active', select=True)
2008-08-28 12:39:04 +02:00
company = fields.Many2One('company.company', 'Company', required=True,
2009-04-07 18:21:24 +02:00
ondelete="RESTRICT")
2010-03-11 16:45:27 +01:00
currency = fields.Function(fields.Many2One('currency.currency',
'Currency'), 'get_currency')
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'get_currency_digits')
2012-04-03 20:06:15 +02:00
second_currency = fields.Many2One('currency.currency',
2013-02-16 18:54:35 +01:00
'Secondary Currency', help='Force all moves for this account \n'
'to have this secondary currency.', ondelete="RESTRICT")
2009-04-07 18:21:24 +02:00
type = fields.Many2One('account.account.type', 'Type', ondelete="RESTRICT",
2011-08-21 11:20:29 +02:00
states={
'invisible': Eval('kind') == 'view',
2011-10-07 20:27:27 +02:00
'required': Eval('kind') != 'view',
2011-08-21 11:20:29 +02:00
},
domain=[
('company', '=', Eval('company')),
], depends=['kind', 'company'])
2012-03-05 10:52:56 +01:00
parent = fields.Many2One('account.account', 'Parent', select=True,
left="left", right="right", ondelete="RESTRICT",
domain=[('company', '=', Eval('company'))],
depends=['company'])
2012-03-05 10:52:56 +01:00
left = fields.Integer('Left', required=True, select=True)
right = fields.Integer('Right', required=True, select=True)
2009-03-19 19:29:19 +01:00
childs = fields.One2Many('account.account', 'parent', 'Children')
2010-03-11 16:45:27 +01:00
balance = fields.Function(fields.Numeric('Balance',
digits=(16, Eval('currency_digits', 2)), depends=['currency_digits']),
'get_balance')
credit = fields.Function(fields.Numeric('Credit',
digits=(16, Eval('currency_digits', 2)), depends=['currency_digits']),
'get_credit_debit')
debit = fields.Function(fields.Numeric('Debit',
digits=(16, Eval('currency_digits', 2)), depends=['currency_digits']),
'get_credit_debit')
2008-03-13 23:22:59 +01:00
reconcile = fields.Boolean('Reconcile',
2013-02-16 18:54:35 +01:00
help='Allow move lines of this account \nto be reconciled.',
2011-08-21 11:20:29 +02:00
states={
'invisible': Eval('kind') == 'view',
}, depends=['kind'])
2008-03-13 23:22:59 +01:00
note = fields.Text('Note')
kind = fields.Selection([
2012-03-30 14:18:10 +02:00
('other', 'Other'),
('payable', 'Payable'),
('revenue', 'Revenue'),
('receivable', 'Receivable'),
('expense', 'Expense'),
('stock', 'Stock'),
('view', 'View'),
], 'Kind', required=True)
2008-09-19 15:00:26 +02:00
deferral = fields.Boolean('Deferral', states={
2011-08-21 11:20:29 +02:00
'invisible': Eval('kind') == 'view',
}, depends=['kind'])
2008-09-19 15:00:26 +02:00
deferrals = fields.One2Many('account.account.deferral', 'account',
2011-08-21 11:20:29 +02:00
'Deferrals', readonly=True, states={
'invisible': Eval('kind') == 'view',
}, depends=['kind'])
party_required = fields.Boolean('Party Required',
states={
'invisible': Eval('kind') == 'view',
},
depends=['kind'])
general_ledger_balance = fields.Boolean('General Ledger Balance',
states={
'invisible': Eval('kind') == 'view',
},
depends=['kind'],
help="Display only the balance in the general ledger report")
template = fields.Many2One('account.account.template', 'Template')
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(Account, cls).__setup__()
cls._error_messages.update({
'delete_account_containing_move_lines': ('You can not delete '
'account "%s" because it has move lines.'),
})
2012-09-24 22:17:29 +02:00
cls._sql_error_messages.update({
'parent_fkey': ('You can not delete accounts that have '
'children.'),
})
2012-09-24 22:17:29 +02:00
cls._order.insert(0, ('code', 'ASC'))
cls._order.insert(1, ('name', 'ASC'))
2008-03-13 23:22:59 +01:00
@classmethod
def validate(cls, accounts):
super(Account, cls).validate(accounts)
cls.check_recursion(accounts)
2012-09-24 22:17:29 +02:00
@staticmethod
def default_left():
return 0
2012-09-24 22:17:29 +02:00
@staticmethod
def default_right():
return 0
2012-09-24 22:17:29 +02:00
@staticmethod
def default_active():
2008-03-13 23:22:59 +01:00
return True
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') or None
2010-08-19 22:02:00 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_reconcile():
return False
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_deferral():
2008-09-19 15:00:26 +02:00
return True
2008-03-13 23:22:59 +01:00
@staticmethod
def default_party_required():
return False
@staticmethod
def default_general_ledger_balance():
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_kind():
return 'view'
2012-09-24 22:17:29 +02:00
def get_currency(self, name):
return self.company.currency.id
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
def get_currency_digits(self, name):
return self.company.currency.digits
2008-07-29 11:40:24 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def get_balance(cls, accounts, name):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
MoveLine = pool.get('account.move.line')
FiscalYear = pool.get('account.fiscalyear')
2010-08-19 22:02:00 +02:00
cursor = Transaction().cursor
2008-09-19 15:00:26 +02:00
2013-09-06 22:33:47 +02:00
table_a = cls.__table__()
table_c = cls.__table__()
line = MoveLine.__table__()
ids = [a.id for a in accounts]
balances = dict((i, 0) for i in ids)
2013-09-06 22:33:47 +02:00
line_query, fiscalyear_ids = MoveLine.query_get(line)
2014-07-17 18:56:39 +02:00
for sub_ids in grouped_slice(ids):
2013-09-06 22:33:47 +02:00
red_sql = reduce_ids(table_a.id, sub_ids)
cursor.execute(*table_a.join(table_c,
condition=(table_c.left >= table_a.left)
& (table_c.right <= table_a.right)
).join(line, condition=line.account == table_c.id
).select(
table_a.id,
Sum(Coalesce(line.debit, 0) - Coalesce(line.credit, 0)),
where=red_sql & line_query & table_c.active,
group_by=table_a.id))
result = cursor.fetchall()
balances.update(dict(result))
2008-03-13 23:22:59 +01:00
# SQLite uses float for SUM
for account_id, balance in balances.iteritems():
if isinstance(balance, Decimal):
break
balances[account_id] = Decimal(str(balance))
2008-03-13 23:22:59 +01:00
2014-01-31 00:02:55 +01:00
for account in accounts:
balances[account.id] = account.company.currency.round(
balances[account.id])
fiscalyears = FiscalYear.browse(fiscalyear_ids)
func = lambda accounts, names: \
{names[0]: cls.get_balance(accounts, names[0])}
return cls._cumulate(fiscalyears, accounts, {name: balances},
func)[name]
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def get_credit_debit(cls, accounts, names):
'''
2012-09-24 22:17:29 +02:00
Function to compute debit, credit for accounts.
If cumulate is set in the context, it is the cumulate amount over all
previous fiscal year.
'''
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
MoveLine = pool.get('account.move.line')
FiscalYear = pool.get('account.fiscalyear')
2010-08-19 22:02:00 +02:00
cursor = Transaction().cursor
2008-03-13 23:22:59 +01:00
result = {}
ids = [a.id for a in accounts]
for name in names:
if name not in ('credit', 'debit'):
raise Exception('Bad argument')
result[name] = dict((i, 0) for i in ids)
2008-03-13 23:22:59 +01:00
2013-09-06 22:33:47 +02:00
table = cls.__table__()
line = MoveLine.__table__()
line_query, fiscalyear_ids = MoveLine.query_get(line)
columns = [table.id]
for name in names:
columns.append(Sum(Coalesce(Column(line, name), 0)))
2014-07-17 18:56:39 +02:00
for sub_ids in grouped_slice(ids):
2013-09-06 22:33:47 +02:00
red_sql = reduce_ids(table.id, sub_ids)
cursor.execute(*table.join(line, 'LEFT',
condition=line.account == table.id
).select(*columns,
where=red_sql & line_query,
group_by=table.id))
for row in cursor.fetchall():
account_id = row[0]
for i, name in enumerate(names, 1):
2009-09-22 16:08:11 +02:00
# SQLite uses float for SUM
if not isinstance(row[i], Decimal):
result[name][account_id] = Decimal(str(row[i]))
else:
result[name][account_id] = row[i]
2014-01-31 00:02:55 +01:00
for account in accounts:
for name in names:
result[name][account.id] = account.company.currency.round(
result[name][account.id])
2008-03-13 23:22:59 +01:00
if not Transaction().context.get('cumulate'):
return result
else:
fiscalyears = FiscalYear.browse(fiscalyear_ids)
return cls._cumulate(fiscalyears, accounts, result,
cls.get_credit_debit)
2008-03-13 23:22:59 +01:00
@classmethod
def _cumulate(cls, fiscalyears, accounts, values, func):
"""
Cumulate previous fiscalyear values into values
func is the method to compute values
"""
pool = Pool()
FiscalYear = pool.get('account.fiscalyear')
Deferral = pool.get('account.account.deferral')
names = values.keys()
youngest_fiscalyear = None
for fiscalyear in fiscalyears:
if (not youngest_fiscalyear
or (youngest_fiscalyear.start_date
> fiscalyear.start_date)):
youngest_fiscalyear = fiscalyear
fiscalyear = None
if youngest_fiscalyear:
fiscalyears = FiscalYear.search([
('end_date', '<=', youngest_fiscalyear.start_date),
('company', '=', youngest_fiscalyear.company),
], order=[('end_date', 'DESC')], limit=1)
if fiscalyears:
fiscalyear, = fiscalyears
if not fiscalyear:
return values
if fiscalyear.state == 'close':
id2deferral = {}
ids = [a.id for a in accounts]
2014-07-17 18:56:39 +02:00
for sub_ids in grouped_slice(ids):
deferrals = Deferral.search([
('fiscalyear', '=', fiscalyear.id),
2014-07-17 18:56:39 +02:00
('account', 'in', list(sub_ids)),
])
for deferral in deferrals:
id2deferral[deferral.account.id] = deferral
for account in accounts:
if account.id in id2deferral:
deferral = id2deferral[account.id]
for name in names:
values[name][account.id] += getattr(deferral, name)
else:
with Transaction().set_context(fiscalyear=fiscalyear.id,
date=None, periods=None):
previous_result = func(accounts, names)
for name in names:
vals = values[name]
for account in accounts:
vals[account.id] += previous_result[name][account.id]
2008-09-19 15:00:26 +02:00
return values
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
def get_rec_name(self, name):
if self.code:
return self.code + ' - ' + self.name
else:
return self.name
2008-03-13 23:22:59 +01: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',
('code',) + tuple(clause[1:]),
(cls._rec_name,) + tuple(clause[1:]),
]
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def copy(cls, accounts, default=None):
if default is None:
default = {}
default['left'] = 0
default['right'] = 0
default.setdefault('template')
2012-11-15 10:46:54 +01:00
default.setdefault('deferrals', [])
2012-09-24 22:17:29 +02:00
new_accounts = super(Account, cls).copy(accounts, default=default)
cls._rebuild_tree('parent', None, 0)
return new_accounts
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
2013-12-19 14:44:33 +01:00
def write(cls, *args):
pool = Pool()
MoveLine = pool.get('account.move.line')
actions = iter(args)
args = []
for accounts, values in zip(actions, actions):
if not values.get('active', True):
childs = cls.search([
('parent', 'child_of', [a.id for a in accounts]),
])
if MoveLine.search([
('account', 'in', [a.id for a in childs]),
]):
values = values.copy()
del values['active']
args.extend((accounts, values))
super(Account, cls).write(*args)
2008-03-13 23:22:59 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def delete(cls, accounts):
MoveLine = Pool().get('account.move.line')
childs = cls.search([
('parent', 'child_of', [a.id for a in accounts]),
])
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,))
2012-09-24 22:17:29 +02:00
super(Account, cls).delete(accounts)
2012-09-24 22:17:29 +02:00
def update_account(self, template2account=None, template2type=None):
'''
Update recursively accounts based on template.
2012-09-24 22:17:29 +02:00
template2account is a dictionary with template id as key and account id
as value, used to convert template id into account. The dictionary is
filled with new accounts.
template2type is a dictionary with type template id as key and type id
as value, used to convert type template id into type.
'''
2012-11-23 18:00:16 +01:00
pool = Pool()
Lang = pool.get('ir.lang')
Config = pool.get('ir.configuration')
if template2account is None:
template2account = {}
if template2type is None:
template2type = {}
2012-09-24 22:17:29 +02:00
if self.template:
vals = self.template._get_account_value(account=self)
2012-10-17 12:33:30 +02:00
current_type = self.type.id if self.type else None
template_type = (template2type.get(self.template.type.id)
if self.template.type else None)
if current_type != template_type:
2012-10-17 12:33:30 +02:00
vals['type'] = template_type
if vals:
2012-09-24 22:17:29 +02:00
self.write([self], vals)
2012-11-23 18:00:16 +01:00
prev_lang = self._context.get('language') or Config.get_language()
prev_data = {}
2012-09-24 22:17:29 +02:00
for field_name, field in self.template._fields.iteritems():
if getattr(field, 'translate', False):
2012-09-24 22:17:29 +02:00
prev_data[field_name] = getattr(self.template, field_name)
for lang in Lang.get_translatable_languages():
if lang == prev_lang:
continue
2012-09-24 22:17:29 +02:00
with Transaction().set_context(language=lang):
account = self.__class__(self.id)
data = {}
for field_name, field in (
account.template._fields.iteritems()):
if (getattr(field, 'translate', False)
and (getattr(account.template, field_name) !=
prev_data[field_name])):
data[field_name] = getattr(account.template,
field_name)
if data:
self.write([account], data)
template2account[self.template.id] = self.id
2012-09-24 22:17:29 +02:00
for child in self.childs:
child.update_account(template2account=template2account,
template2type=template2type)
2012-09-24 22:17:29 +02:00
def update_account_taxes(self, template2account, template2tax):
'''
Update recursively account taxes base on template.
2012-09-24 22:17:29 +02:00
template2account is a dictionary with template id as key and account id
as value, used to convert template id into account.
template2tax is a dictionary with tax template id as key and tax id as
value, used to convert tax template id into tax.
'''
if template2account is None:
template2account = {}
if template2tax is None:
template2tax = {}
2012-09-24 22:17:29 +02:00
if self.template:
if self.template.taxes:
tax_ids = [template2tax[x.id] for x in self.template.taxes
if x.id in template2tax]
2012-09-24 22:17:29 +02:00
old_tax_ids = [x.id for x in self.taxes]
for tax_id in tax_ids:
if tax_id not in old_tax_ids:
2012-09-24 22:17:29 +02:00
self.write([self], {
'taxes': [
2012-09-24 22:17:29 +02:00
('add', template2tax[x.id])
for x in self.template.taxes
if x.id in template2tax],
})
break
2012-09-24 22:17:29 +02:00
for child in self.childs:
child.update_account_taxes(template2account, template2tax)
2009-02-28 16:57:10 +01:00
class AccountDeferral(ModelSQL, ModelView):
2008-09-19 15:00:26 +02:00
'''
Account Deferral
It is used to deferral the debit/credit of account by fiscal year.
'''
2012-09-24 22:17:29 +02:00
__name__ = 'account.account.deferral'
2008-09-19 15:00:26 +02:00
account = fields.Many2One('account.account', 'Account', required=True,
2012-03-05 10:52:56 +01:00
select=True)
2008-09-19 15:00:26 +02:00
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2012-03-05 10:52:56 +01:00
required=True, select=True)
2010-01-20 10:56:33 +01:00
debit = fields.Numeric('Debit', digits=(16, Eval('currency_digits', 2)),
required=True, depends=['currency_digits'])
2010-01-20 10:56:33 +01:00
credit = fields.Numeric('Credit', digits=(16, Eval('currency_digits', 2)),
required=True, depends=['currency_digits'])
balance = fields.Function(fields.Numeric('Balance',
digits=(16, Eval('currency_digits', 2)),
depends=['currency_digits']), 'get_balance')
2010-03-11 16:45:27 +01:00
currency_digits = fields.Function(fields.Integer('Currency Digits'),
'get_currency_digits')
2008-09-19 15:00:26 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(AccountDeferral, cls).__setup__()
cls._sql_constraints += [
2008-09-19 15:00:26 +02:00
('deferral_uniq', 'UNIQUE(account, fiscalyear)',
'Deferral must be unique by account and fiscal year'),
]
2012-09-24 22:17:29 +02:00
cls._error_messages.update({
2008-09-22 18:45:22 +02:00
'write_deferral': 'You can not modify Account Deferral records',
})
2008-09-19 15:00:26 +02:00
def get_balance(self, name):
return self.debit - self.credit
2012-09-24 22:17:29 +02:00
def get_currency_digits(self, name):
return self.account.currency_digits
2008-09-22 18:41:00 +02:00
2012-09-24 22:17:29 +02:00
def get_rec_name(self, name):
return '%s - %s' % (self.account.rec_name, self.fiscalyear.rec_name)
2008-09-19 15:00:26 +02: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',
('account.rec_name',) + tuple(clause[1:]),
('fiscalyear.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, deferrals, values, *args):
2012-09-24 22:17:29 +02:00
cls.raise_user_error('write_deferral')
2008-09-19 15:00:26 +02:00
2012-01-02 17:54:33 +01:00
class OpenChartAccountStart(ModelView):
'Open Chart of Accounts'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_chart.start'
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2009-03-20 12:59:53 +01:00
help='Leave empty for all open fiscal year')
2013-07-14 21:00:07 +02:00
posted = fields.Boolean('Posted Moves', help='Show posted moves only')
2008-03-28 17:39:54 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
2008-03-28 17:39:54 +01:00
return False
class OpenChartAccount(Wizard):
2012-01-02 17:54:33 +01:00
'Open Chart of Accounts'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_chart'
2012-01-02 17:54:33 +01:00
start = StateView('account.open_chart.start',
'account.open_chart_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('account.act_account_tree2')
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
2012-01-02 17:54:33 +01:00
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:17:29 +02:00
'fiscalyear': (self.start.fiscalyear.id
if self.start.fiscalyear else None),
'posted': self.start.posted,
2008-03-28 17:39:54 +01:00
})
2012-09-27 11:07:08 +02:00
if self.start.fiscalyear:
action['name'] += ' - %s' % self.start.fiscalyear.rec_name
if self.start.posted:
action['name'] += '*'
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'
2012-10-17 23:54:35 +02:00
class PrintGeneralLedgerStart(ModelView):
'Print General Ledger'
2012-09-24 22:17:29 +02:00
__name__ = 'account.print_general_ledger.start'
2008-03-28 17:25:14 +01:00
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2014-01-26 14:28:46 +01:00
required=True)
2008-03-28 17:25:14 +01:00
start_period = fields.Many2One('account.period', 'Start Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '<=', (Eval('end_period'), 'start_date')),
], depends=['fiscalyear', 'end_period'])
2008-03-28 17:25:14 +01:00
end_period = fields.Many2One('account.period', 'End Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '>=', (Eval('start_period'), 'start_date'))
],
depends=['fiscalyear', 'start_period'])
2008-03-28 17:25:14 +01:00
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')
empty_account = fields.Boolean('Empty Account',
help='With account without move')
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_fiscalyear():
FiscalYear = Pool().get('account.fiscalyear')
return FiscalYear.find(
Transaction().context.get('company'), exception=False)
2008-03-28 17:25:14 +01: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')
2010-08-19 22:02:00 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
2008-03-28 17:25:14 +01:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_empty_account():
2008-03-28 17:25:14 +01:00
return False
2014-01-26 14:28:46 +01:00
@fields.depends('fiscalyear')
2012-09-24 22:17:29 +02:00
def on_change_fiscalyear(self):
2014-10-29 20:39:03 +01:00
self.start_period = None
self.end_period = None
2008-03-28 17:25:14 +01:00
2012-10-17 23:54:35 +02:00
class PrintGeneralLedger(Wizard):
'Print General Ledger'
2012-09-24 22:17:29 +02:00
__name__ = 'account.print_general_ledger'
2012-01-02 17:54:33 +01:00
start = StateView('account.print_general_ledger.start',
'account.print_general_ledger_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateAction('account.report_general_ledger')
2012-09-24 22:17:29 +02:00
def do_print_(self, action):
if self.start.start_period:
start_period = self.start.start_period.id
2012-01-02 17:54:33 +01:00
else:
2012-03-27 10:43:03 +02:00
start_period = None
2012-09-24 22:17:29 +02:00
if self.start.end_period:
end_period = self.start.end_period.id
2012-01-02 17:54:33 +01:00
else:
2012-03-27 10:43:03 +02:00
end_period = None
2012-01-02 17:54:33 +01:00
data = {
2012-09-24 22:17:29 +02:00
'company': self.start.company.id,
'fiscalyear': self.start.fiscalyear.id,
2012-01-02 17:54:33 +01:00
'start_period': start_period,
'end_period': end_period,
2012-09-24 22:17:29 +02:00
'posted': self.start.posted,
'empty_account': self.start.empty_account,
2012-01-02 17:54:33 +01:00
}
return action, data
2012-09-24 22:17:29 +02:00
def transition_print_(self):
2012-01-02 17:54:33 +01:00
return 'end'
2008-03-28 17:25:14 +01:00
2012-10-17 23:54:35 +02:00
class GeneralLedger(Report):
2012-09-24 22:17:29 +02:00
__name__ = 'account.general_ledger'
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def parse(cls, report, objects, data, localcontext):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Account = pool.get('account.account')
Period = pool.get('account.period')
Company = pool.get('company.company')
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
company = Company(data['company'])
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
accounts = Account.search([
2012-01-02 17:54:33 +01:00
('company', '=', data['company']),
('kind', '!=', 'view'),
], order=[('code', 'ASC'), ('id', 'ASC')])
2008-03-28 17:25:14 +01:00
start_period_ids = [0]
2012-09-24 22:17:29 +02:00
start_periods = []
2012-01-02 17:54:33 +01:00
if data['start_period']:
2012-09-24 22:17:29 +02:00
start_period = Period(data['start_period'])
start_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
('end_date', '<=', start_period.start_date),
])
2012-09-24 22:17:29 +02:00
start_period_ids = [p.id for p in start_periods]
else:
start_period = None
2008-03-28 17:25:14 +01:00
2010-08-19 22:02:00 +02:00
with Transaction().set_context(
2012-01-02 17:54:33 +01:00
fiscalyear=data['fiscalyear'],
2010-08-19 22:02:00 +02:00
periods=start_period_ids,
2012-01-02 17:54:33 +01:00
posted=data['posted']):
2012-09-24 22:17:29 +02:00
start_accounts = Account.browse(accounts)
2008-03-28 17:25:14 +01:00
id2start_account = {}
for account in start_accounts:
id2start_account[account.id] = account
end_period_ids = []
2012-01-02 17:54:33 +01:00
if data['end_period']:
2012-09-24 22:17:29 +02:00
end_period = Period(data['end_period'])
end_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
('end_date', '<=', end_period.start_date),
])
2012-09-24 22:17:29 +02:00
if end_period not in end_periods:
end_periods.append(end_period)
2008-03-28 17:25:14 +01:00
else:
2012-09-24 22:17:29 +02:00
end_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
])
end_period = None
2012-09-24 22:17:29 +02:00
end_period_ids = [p.id for p in end_periods]
2008-03-28 17:25:14 +01:00
2010-08-19 22:02:00 +02:00
with Transaction().set_context(
2012-01-02 17:54:33 +01:00
fiscalyear=data['fiscalyear'],
2010-08-19 22:02:00 +02:00
periods=end_period_ids,
2012-01-02 17:54:33 +01:00
posted=data['posted']):
2012-09-24 22:17:29 +02:00
end_accounts = Account.browse(accounts)
2008-03-28 17:25:14 +01:00
id2end_account = {}
for account in end_accounts:
id2end_account[account.id] = account
2012-01-02 17:54:33 +01:00
if not data['empty_account']:
2013-09-17 10:49:25 +02:00
account2lines = dict(cls.get_lines(accounts,
end_periods, data['posted']))
2014-01-20 12:27:15 -05:00
accounts = Account.browse([a.id for a in accounts
if a in account2lines])
2010-03-12 14:14:53 +01:00
account_id2lines = cls.lines(
[a for a in accounts if not a.general_ledger_balance],
2012-09-24 22:17:29 +02:00
list(set(end_periods).difference(set(start_periods))),
2012-01-02 17:54:33 +01:00
data['posted'])
2012-09-24 22:17:29 +02:00
localcontext['accounts'] = accounts
2010-08-19 22:02:00 +02:00
localcontext['id2start_account'] = id2start_account
localcontext['id2end_account'] = id2end_account
localcontext['digits'] = company.currency.digits
localcontext['lines'] = lambda account_id: account_id2lines[account_id]
localcontext['company'] = company
localcontext['start_period'] = start_period
localcontext['end_period'] = end_period
2008-03-28 17:25:14 +01:00
2012-10-17 23:54:35 +02:00
return super(GeneralLedger, cls).parse(report, objects, data,
2012-01-02 17:54:33 +01:00
localcontext)
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
@classmethod
def get_lines(cls, accounts, periods, posted):
MoveLine = Pool().get('account.move.line')
2008-03-28 17:25:14 +01:00
clause = [
2012-09-24 22:17:29 +02:00
('account', 'in', [a.id for a in accounts]),
('period', 'in', [p.id for p in periods]),
2008-03-28 17:25:14 +01:00
('state', '!=', 'draft'),
]
if posted:
clause.append(('move.state', '=', 'posted'))
2013-09-17 10:49:25 +02:00
lines = MoveLine.search(clause,
order=[
2014-04-18 19:36:05 +02:00
('account', 'ASC'), # TODO replace by account.id
2013-09-17 10:49:25 +02:00
('date', 'ASC'),
])
2014-04-18 19:36:05 +02:00
key = operator.attrgetter('account')
lines.sort(key=key)
return groupby(lines, key)
2012-09-24 22:17:29 +02:00
@classmethod
def lines(cls, accounts, periods, posted):
Move = Pool().get('account.move')
res = dict((a.id, []) for a in accounts)
account2lines = cls.get_lines(accounts, periods, posted)
2008-03-28 17:25:14 +01:00
2012-09-24 22:17:29 +02:00
state_selections = dict(Move.fields_get(
fields_names=['state'])['state']['selection'])
2013-09-17 10:49:25 +02:00
for account, lines in account2lines:
balance = Decimal('0.0')
for line in lines:
balance += line.debit - line.credit
2012-09-24 22:17:29 +02:00
res[account.id].append({
2012-04-03 20:06:15 +02:00
'date': line.date,
2013-03-21 18:37:14 +01:00
'move': line.move.rec_name,
2012-04-03 20:06:15 +02:00
'debit': line.debit,
'credit': line.credit,
'balance': balance,
2013-03-21 18:37:14 +01:00
'description': '\n'.join(
(line.move.description or '',
line.description or '')).strip(),
'origin': (line.move.origin.rec_name
if line.move.origin else ''),
2012-04-03 20:06:15 +02:00
'state': state_selections.get(line.move.state,
line.move.state),
})
2008-03-28 17:25:14 +01:00
return res
2012-01-02 17:54:33 +01:00
class PrintTrialBalanceStart(ModelView):
'Print Trial Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.print_trial_balance.start'
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2014-01-26 14:28:46 +01:00
required=True)
start_period = fields.Many2One('account.period', 'Start Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '<=', (Eval('end_period'), 'start_date'))
2010-01-20 10:56:33 +01:00
],
2011-08-04 16:57:14 +02:00
depends=['end_period', 'fiscalyear'])
end_period = fields.Many2One('account.period', 'End Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '>=', (Eval('start_period'), 'start_date'))
2010-01-20 10:56:33 +01:00
],
2011-08-04 16:57:14 +02:00
depends=['start_period', 'fiscalyear'])
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')
empty_account = fields.Boolean('Empty Account',
help='With account without move')
2012-09-24 22:17:29 +02:00
@staticmethod
def default_fiscalyear():
FiscalYear = Pool().get('account.fiscalyear')
return FiscalYear.find(
Transaction().context.get('company'), exception=False)
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')
2010-08-19 22:02:00 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_empty_account():
return False
2014-01-26 14:28:46 +01:00
@fields.depends('fiscalyear')
2012-09-24 22:17:29 +02:00
def on_change_fiscalyear(self):
2014-10-29 20:39:03 +01:00
self.start_period = None
self.end_period = None
class PrintTrialBalance(Wizard):
'Print Trial Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.print_trial_balance'
2012-01-02 17:54:33 +01:00
start = StateView('account.print_trial_balance.start',
2012-10-12 11:44:27 +02:00
'account.print_trial_balance_start_view_form', [
2012-01-02 17:54:33 +01:00
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateAction('account.report_trial_balance')
2012-09-24 22:17:29 +02:00
def do_print_(self, action):
if self.start.start_period:
start_period = self.start.start_period.id
2012-01-02 17:54:33 +01:00
else:
2012-03-27 10:43:03 +02:00
start_period = None
2012-09-24 22:17:29 +02:00
if self.start.end_period:
end_period = self.start.end_period.id
2012-01-02 17:54:33 +01:00
else:
2012-03-27 10:43:03 +02:00
end_period = None
2012-01-02 17:54:33 +01:00
data = {
2012-09-24 22:17:29 +02:00
'company': self.start.company.id,
'fiscalyear': self.start.fiscalyear.id,
2012-01-02 17:54:33 +01:00
'start_period': start_period,
'end_period': end_period,
2012-09-24 22:17:29 +02:00
'posted': self.start.posted,
'empty_account': self.start.empty_account,
2012-01-02 17:54:33 +01:00
}
return action, data
2012-09-24 22:17:29 +02:00
def transition_print_(self):
2012-01-02 17:54:33 +01:00
return 'end'
class TrialBalance(Report):
2012-09-24 22:17:29 +02:00
__name__ = 'account.trial_balance'
2012-09-24 22:17:29 +02:00
@classmethod
def parse(cls, report, objects, data, localcontext):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Account = pool.get('account.account')
Period = pool.get('account.period')
Company = pool.get('company.company')
2012-09-24 22:17:29 +02:00
company = Company(data['company'])
2012-09-24 22:17:29 +02:00
accounts = Account.search([
('company', '=', data['company']),
('kind', '!=', 'view'),
])
2012-09-24 22:17:29 +02:00
start_periods = []
2012-01-02 17:54:33 +01:00
if data['start_period']:
2012-09-24 22:17:29 +02:00
start_period = Period(data['start_period'])
start_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
('end_date', '<=', start_period.start_date),
])
2012-01-02 17:54:33 +01:00
if data['end_period']:
2012-09-24 22:17:29 +02:00
end_period = Period(data['end_period'])
end_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
('end_date', '<=', end_period.start_date),
])
2012-09-24 22:17:29 +02:00
end_periods = list(set(end_periods).difference(
set(start_periods)))
if end_period not in end_periods:
end_periods.append(end_period)
else:
2012-09-24 22:17:29 +02:00
end_periods = Period.search([
2012-01-02 17:54:33 +01:00
('fiscalyear', '=', data['fiscalyear']),
])
2012-09-24 22:17:29 +02:00
end_periods = list(set(end_periods).difference(
set(start_periods)))
start_period_ids = [p.id for p in start_periods] or [0]
end_period_ids = [p.id for p in end_periods]
2012-08-16 15:51:58 +02:00
with Transaction().set_context(
fiscalyear=data['fiscalyear'],
periods=start_period_ids,
posted=data['posted']):
2012-09-24 22:17:29 +02:00
start_accounts = Account.browse(accounts)
2012-08-16 15:51:58 +02:00
2010-08-19 22:02:00 +02:00
with Transaction().set_context(
fiscalyear=None,
2010-08-19 22:02:00 +02:00
periods=end_period_ids,
2012-01-02 17:54:33 +01:00
posted=data['posted']):
2012-09-24 22:17:29 +02:00
in_accounts = Account.browse(accounts)
2012-08-16 15:51:58 +02:00
with Transaction().set_context(
fiscalyear=data['fiscalyear'],
periods=start_period_ids + end_period_ids,
posted=data['posted']):
2012-09-24 22:17:29 +02:00
end_accounts = Account.browse(accounts)
2012-08-16 15:51:58 +02:00
to_remove = set()
2012-01-02 17:54:33 +01:00
if not data['empty_account']:
2012-08-16 15:51:58 +02:00
for account in in_accounts:
if account.debit == Decimal('0.0') \
and account.credit == Decimal('0.0'):
to_remove.add(account)
2012-08-16 15:51:58 +02:00
accounts = []
for start_account, in_account, end_account in izip(
start_accounts, in_accounts, end_accounts):
if in_account in to_remove:
2012-08-16 15:51:58 +02:00
continue
accounts.append({
'code': start_account.code,
'name': start_account.name,
'start_balance': start_account.balance,
'debit': in_account.debit,
'credit': in_account.credit,
'end_balance': end_account.balance,
})
2012-09-24 22:17:29 +02:00
periods = end_periods
2010-08-19 22:02:00 +02:00
localcontext['accounts'] = accounts
periods.sort(key=operator.attrgetter('start_date'))
2010-08-19 22:02:00 +02:00
localcontext['start_period'] = periods[0]
periods.sort(key=operator.attrgetter('end_date'))
2010-08-19 22:02:00 +02:00
localcontext['end_period'] = periods[-1]
localcontext['company'] = company
localcontext['digits'] = company.currency.digits
2012-09-24 22:17:29 +02:00
localcontext['sum'] = lambda accounts, field: cls.sum(accounts, field)
2012-09-24 22:17:29 +02:00
return super(TrialBalance, cls).parse(report, objects, data,
2012-01-02 17:54:33 +01:00
localcontext)
2012-09-24 22:17:29 +02:00
@classmethod
def sum(cls, accounts, field):
amount = Decimal('0.0')
for account in accounts:
amount += account[field]
return amount
2012-01-02 17:54:33 +01:00
class OpenBalanceSheetStart(ModelView):
'Open Balance Sheet'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_balance_sheet.start'
date = fields.Date('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')
2012-09-24 22:17:29 +02:00
@staticmethod
def default_date():
Date_ = Pool().get('ir.date')
return Date_.today()
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')
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
return False
class OpenBalanceSheet(Wizard):
'Open Balance Sheet'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_balance_sheet'
2012-01-02 17:54:33 +01:00
start = StateView('account.open_balance_sheet.start',
'account.open_balance_sheet_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('account.act_account_balance_sheet_tree')
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Lang = pool.get('ir.lang')
2012-09-24 22:17:29 +02:00
company = self.start.company
lang, = Lang.search([
2012-01-27 21:13:00 +01:00
('code', '=', Transaction().language),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
date = Lang.strftime(self.start.date, lang.code, lang.date)
2008-08-27 17:35:39 +02:00
2012-01-02 17:54:33 +01:00
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:17:29 +02:00
'date': Date(self.start.date.year,
self.start.date.month,
self.start.date.day),
'posted': self.start.posted,
2012-01-02 17:54:33 +01:00
'company': company.id,
2013-09-12 18:57:18 +02:00
'cumulate': True,
2012-01-02 17:54:33 +01:00
})
2013-03-26 21:08:34 +01:00
action['name'] += ' %s - %s' % (date, company.rec_name)
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'
2012-01-02 17:54:33 +01:00
class OpenIncomeStatementStart(ModelView):
'Open Income Statement'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_income_statement.start'
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
2014-01-26 14:28:46 +01:00
required=True)
start_period = fields.Many2One('account.period', 'Start Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '<=', (Eval('end_period'), 'start_date'))
2010-01-20 10:56:33 +01:00
],
2011-08-04 16:57:14 +02:00
depends=['end_period', 'fiscalyear'])
end_period = fields.Many2One('account.period', 'End Period',
2011-08-04 16:57:14 +02:00
domain=[
('fiscalyear', '=', Eval('fiscalyear')),
('start_date', '>=', (Eval('start_period'), 'start_date')),
2010-01-20 10:56:33 +01:00
],
2011-08-04 16:57:14 +02:00
depends=['start_period', 'fiscalyear'])
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')
2012-09-24 22:17:29 +02:00
@staticmethod
def default_fiscalyear():
FiscalYear = Pool().get('account.fiscalyear')
return FiscalYear.find(
Transaction().context.get('company'), exception=False)
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')
2010-08-19 22:02:00 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
return False
2014-01-26 14:28:46 +01:00
@fields.depends('fiscalyear')
2012-09-24 22:17:29 +02:00
def on_change_fiscalyear(self):
2014-10-29 20:39:03 +01:00
self.start_period = None
self.end_period = None
class OpenIncomeStatement(Wizard):
'Open Income Statement'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_income_statement'
2012-01-02 17:54:33 +01:00
start = StateView('account.open_income_statement.start',
'account.open_income_statement_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Open', 'open_', 'tryton-ok', default=True),
])
open_ = StateAction('account.act_account_income_statement_tree')
2012-09-24 22:17:29 +02:00
def do_open_(self, action):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Period = pool.get('account.period')
2012-09-24 22:17:29 +02:00
start_periods = []
if self.start.start_period:
start_periods = Period.search([
('fiscalyear', '=', self.start.fiscalyear.id),
('end_date', '<=', self.start.start_period.start_date),
2012-01-02 17:54:33 +01:00
])
2012-09-24 22:17:29 +02:00
end_periods = []
if self.start.end_period:
end_periods = Period.search([
('fiscalyear', '=', self.start.fiscalyear.id),
('end_date', '<=', self.start.end_period.start_date),
2012-01-02 17:54:33 +01:00
])
2012-09-24 22:17:29 +02:00
end_periods = list(set(end_periods).difference(
set(start_periods)))
if self.start.end_period not in end_periods:
end_periods.append(self.start.end_period)
else:
2012-09-24 22:17:29 +02:00
end_periods = Period.search([
('fiscalyear', '=', self.start.fiscalyear.id),
2012-01-02 17:54:33 +01:00
])
2012-09-24 22:17:29 +02:00
end_periods = list(set(end_periods).difference(
set(start_periods)))
2012-01-02 17:54:33 +01:00
action['pyson_context'] = PYSONEncoder().encode({
2012-09-24 22:17:29 +02:00
'periods': [p.id for p in end_periods],
'posted': self.start.posted,
'company': self.start.company.id,
2012-01-02 17:54:33 +01:00
})
return action, {}
2012-01-02 17:54:33 +01:00
class CreateChartStart(ModelView):
'Create Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.create_chart.start'
2012-01-02 17:54:33 +01:00
class CreateChartAccount(ModelView):
'Create Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.create_chart.account'
2014-01-04 19:33:21 +01:00
company = fields.Many2One('company.company', 'Company', required=True)
account_template = fields.Many2One('account.account.template',
2012-03-27 10:43:03 +02:00
'Account Template', required=True, domain=[('parent', '=', None)])
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')
2012-09-24 22:17:29 +02:00
class CreateChartProperties(ModelView):
2012-01-02 17:54:33 +01:00
'Create Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.create_chart.properties'
company = fields.Many2One('company.company', 'Company')
account_receivable = fields.Many2One('account.account',
'Default Receivable Account',
2010-01-20 10:56:33 +01:00
domain=[
('kind', '=', 'receivable'),
('company', '=', Eval('company')),
],
depends=['company'])
account_payable = fields.Many2One('account.account',
'Default Payable Account',
2010-01-20 10:56:33 +01:00
domain=[
('kind', '=', 'payable'),
('company', '=', Eval('company')),
],
depends=['company'])
2012-01-02 17:54:33 +01:00
class CreateChart(Wizard):
'Create Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.create_chart'
2012-01-02 17:54:33 +01:00
start = StateView('account.create_chart.start',
'account.create_chart_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'account', 'tryton-ok', default=True),
])
account = StateView('account.create_chart.account',
'account.create_chart_account_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Create', 'create_account', 'tryton-ok', default=True),
])
create_account = StateTransition()
properties = StateView('account.create_chart.properties',
'account.create_chart_properties_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Create', 'create_properties', 'tryton-ok', default=True),
])
create_properties = StateTransition()
2012-09-24 22:17:29 +02:00
def transition_create_account(self):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
TaxCodeTemplate = pool.get('account.tax.code.template')
TaxTemplate = pool.get('account.tax.template')
TaxRuleTemplate = pool.get('account.tax.rule.template')
TaxRuleLineTemplate = \
2013-02-16 18:54:35 +01:00
pool.get('account.tax.rule.line.template')
2012-11-23 18:00:16 +01:00
Config = pool.get('ir.configuration')
2008-07-21 13:59:50 +02:00
with Transaction().set_context(language=Config.get_language(),
company=self.account.company.id):
2012-09-24 22:17:29 +02:00
account_template = self.account.account_template
2010-08-19 22:02:00 +02:00
# Create account types
template2type = {}
2012-09-24 22:17:29 +02:00
account_template.type.create_type(self.account.company.id,
template2type=template2type)
2008-08-28 12:39:04 +02:00
2010-08-19 22:02:00 +02:00
# Create accounts
template2account = {}
2012-09-24 22:17:29 +02:00
account_template.create_account(self.account.company.id,
template2account=template2account, template2type=template2type)
2008-07-21 13:59:50 +02:00
2010-08-19 22:02:00 +02:00
# Create tax codes
template2tax_code = {}
2012-09-24 22:17:29 +02:00
tax_code_templates = TaxCodeTemplate.search([
2012-01-02 17:54:33 +01:00
('account', '=', account_template.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2012-01-02 17:54:33 +01:00
])
2012-09-24 22:17:29 +02:00
for tax_code_template in tax_code_templates:
tax_code_template.create_tax_code(self.account.company.id,
2012-01-02 17:54:33 +01:00
template2tax_code=template2tax_code)
2010-08-19 22:02:00 +02:00
# Create taxes
template2tax = {}
2012-09-24 22:17:29 +02:00
tax_templates = TaxTemplate.search([
2012-01-02 17:54:33 +01:00
('account', '=', account_template.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2012-01-02 17:54:33 +01:00
])
2012-09-24 22:17:29 +02:00
for tax_template in tax_templates:
tax_template.create_tax(self.account.company.id,
2012-01-02 17:54:33 +01:00
template2tax_code=template2tax_code,
template2account=template2account,
template2tax=template2tax)
2010-08-19 22:02:00 +02:00
# Update taxes on accounts
2012-09-24 22:17:29 +02:00
account_template.update_account_taxes(template2account,
template2tax)
2010-08-19 22:02:00 +02:00
# Create tax rules
template2rule = {}
2012-09-24 22:17:29 +02:00
tax_rule_templates = TaxRuleTemplate.search([
2012-01-02 17:54:33 +01:00
('account', '=', account_template.id),
])
2012-09-24 22:17:29 +02:00
for tax_rule_template in tax_rule_templates:
tax_rule_template.create_rule(self.account.company.id,
template2rule=template2rule)
2010-08-19 22:02:00 +02:00
# Create tax rule lines
template2rule_line = {}
2012-09-24 22:17:29 +02:00
tax_rule_line_templates = TaxRuleLineTemplate.search([
2012-01-02 17:54:33 +01:00
('rule.account', '=', account_template.id),
])
2012-09-24 22:17:29 +02:00
for tax_rule_line_template in tax_rule_line_templates:
tax_rule_line_template.create_rule_line(template2tax,
template2rule, template2rule_line=template2rule_line)
2012-01-02 17:54:33 +01:00
return 'properties'
2012-09-24 22:17:29 +02:00
def default_properties(self, fields):
2012-01-02 17:54:33 +01:00
return {
2012-09-24 22:17:29 +02:00
'company': self.account.company.id,
2012-01-02 17:54:33 +01:00
}
2012-09-24 22:17:29 +02:00
def transition_create_properties(self):
2012-01-02 17:54:33 +01:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Property = pool.get('ir.property')
ModelField = pool.get('ir.model.field')
2012-09-24 22:17:29 +02:00
with Transaction().set_context(company=self.properties.company.id):
account_receivable_field, = ModelField.search([
('model.model', '=', 'party.party'),
('name', '=', 'account_receivable'),
], limit=1)
2012-09-24 22:17:29 +02:00
properties = Property.search([
('field', '=', account_receivable_field.id),
('res', '=', None),
2012-09-24 22:17:29 +02:00
('company', '=', self.properties.company.id),
])
2014-09-17 21:44:51 +02:00
Property.delete(properties)
if self.properties.account_receivable:
Property.create([{
'field': account_receivable_field.id,
'value': str(
self.properties.account_receivable),
'company': self.properties.company.id,
}])
2012-09-24 22:17:29 +02:00
account_payable_field, = ModelField.search([
('model.model', '=', 'party.party'),
('name', '=', 'account_payable'),
], limit=1)
2012-09-24 22:17:29 +02:00
properties = Property.search([
('field', '=', account_payable_field.id),
('res', '=', None),
2012-09-24 22:17:29 +02:00
('company', '=', self.properties.company.id),
])
2014-09-17 21:44:51 +02:00
Property.delete(properties)
if self.properties.account_payable:
Property.create([{
'field': account_payable_field.id,
'value': str(self.properties.account_payable),
'company': self.properties.company.id,
}])
2012-01-02 17:54:33 +01:00
return 'end'
2008-07-17 17:02:17 +02:00
2012-01-02 17:54:33 +01:00
class UpdateChartStart(ModelView):
'Update Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.update_chart.start'
2009-10-01 12:51:51 +02:00
account = fields.Many2One('account.account', 'Root Account',
2012-03-27 10:43:03 +02:00
required=True, domain=[('parent', '=', None)])
2012-01-02 17:54:33 +01:00
class UpdateChartSucceed(ModelView):
'Update Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.update_chart.succeed'
2012-01-02 17:54:33 +01:00
class UpdateChart(Wizard):
'Update Chart'
2012-09-24 22:17:29 +02:00
__name__ = 'account.update_chart'
2012-01-02 17:54:33 +01:00
start = StateView('account.update_chart.start',
'account.update_chart_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Update', 'update', 'tryton-ok', default=True),
])
update = StateTransition()
succeed = StateView('account.update_chart.succeed',
'account.update_chart_succeed_view_form', [
Button('Ok', 'end', 'tryton-ok', default=True),
])
2012-09-24 22:17:29 +02:00
def transition_update(self):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
TaxCode = pool.get('account.tax.code')
TaxCodeTemplate = pool.get('account.tax.code.template')
Tax = pool.get('account.tax')
TaxTemplate = pool.get('account.tax.template')
TaxRule = pool.get('account.tax.rule')
TaxRuleTemplate = pool.get('account.tax.rule.template')
TaxRuleLine = pool.get('account.tax.rule.line')
TaxRuleLineTemplate = \
2013-02-16 18:54:35 +01:00
pool.get('account.tax.rule.line.template')
2012-09-24 22:17:29 +02:00
account = self.start.account
# Update account types
template2type = {}
2012-09-24 22:17:29 +02:00
account.type.update_type(template2type=template2type)
# Create missing account types
if account.type.template:
2012-09-24 22:17:29 +02:00
account.type.template.create_type(account.company.id,
template2type=template2type)
# Update accounts
template2account = {}
2012-09-24 22:17:29 +02:00
account.update_account(template2account=template2account,
template2type=template2type)
# Create missing accounts
if account.template:
2012-09-24 22:17:29 +02:00
account.template.create_account(account.company.id,
template2account=template2account, template2type=template2type)
# Update tax codes
template2tax_code = {}
2012-09-24 22:17:29 +02:00
tax_codes = TaxCode.search([
('company', '=', account.company.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_code in tax_codes:
tax_code.update_tax_code(template2tax_code=template2tax_code)
# Create missing tax codes
if account.template:
2012-09-24 22:17:29 +02:00
tax_code_templates = TaxCodeTemplate.search([
('account', '=', account.template.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_code_template in tax_code_templates:
tax_code_template.create_tax_code(account.company.id,
template2tax_code=template2tax_code)
# Update taxes
template2tax = {}
2012-09-24 22:17:29 +02:00
taxes = Tax.search([
('company', '=', account.company.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax in taxes:
tax.update_tax(template2tax_code=template2tax_code,
template2account=template2account,
template2tax=template2tax)
# Create missing taxes
if account.template:
2012-09-24 22:17:29 +02:00
tax_templates = TaxTemplate.search([
('account', '=', account.template.id),
2012-03-27 10:43:03 +02:00
('parent', '=', None),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_template in tax_templates:
tax_template.create_tax(account.company.id,
2010-08-19 22:02:00 +02:00
template2tax_code=template2tax_code,
template2account=template2account,
template2tax=template2tax)
# Update taxes on accounts
2012-09-24 22:17:29 +02:00
account.update_account_taxes(template2account, template2tax)
# Update tax rules
template2rule = {}
2012-09-24 22:17:29 +02:00
tax_rules = TaxRule.search([
('company', '=', account.company.id),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_rule in tax_rules:
tax_rule.update_rule(template2rule=template2rule)
# Create missing tax rules
if account.template:
2012-09-24 22:17:29 +02:00
tax_rule_templates = TaxRuleTemplate.search([
('account', '=', account.template.id),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_rule_template in tax_rule_templates:
tax_rule_template.create_rule(account.company.id,
template2rule=template2rule)
# Update tax rule lines
template2rule_line = {}
2012-09-24 22:17:29 +02:00
tax_rule_lines = TaxRuleLine.search([
('rule.company', '=', account.company.id),
2010-08-19 22:02:00 +02:00
])
2012-09-24 22:17:29 +02:00
for tax_rule_line in tax_rule_lines:
tax_rule_line.update_rule_line(template2tax, template2rule,
template2rule_line=template2rule_line)
# Create missing tax rule lines
if account.template:
2012-09-24 22:17:29 +02:00
tax_rule_line_templates = TaxRuleLineTemplate.search([
2010-08-19 22:02:00 +02:00
('rule.account', '=', account.template.id),
])
2012-09-24 22:17:29 +02:00
for tax_rule_line_template in tax_rule_line_templates:
tax_rule_line_template.create_rule_line(template2tax,
template2rule, template2rule_line=template2rule_line)
2012-01-02 17:54:33 +01:00
return 'succeed'
2012-01-02 17:54:33 +01:00
class OpenThirdPartyBalanceStart(ModelView):
'Open Third Party Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_third_party_balance.start'
2008-07-17 17:02:17 +02:00
company = fields.Many2One('company.company', 'Company', required=True)
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
required=True)
2009-03-20 13:49:25 +01:00
posted = fields.Boolean('Posted Move', help='Show only posted move')
2008-07-17 17:02:17 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_fiscalyear():
Fiscalyear = Pool().get('account.fiscalyear')
return Fiscalyear.find(
Transaction().context.get('company'), exception=False)
2008-07-17 17:02:17 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
2008-07-17 17:02:17 +02:00
return False
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-07-17 17:02:17 +02:00
class OpenThirdPartyBalance(Wizard):
'Open Third Party Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_third_party_balance'
2012-01-02 17:54:33 +01:00
start = StateView('account.open_third_party_balance.start',
'account.open_balance_sheet_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateAction('account.report_third_party_balance')
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,
'fiscalyear': self.start.fiscalyear.id,
'posted': self.start.posted,
2012-01-02 17:54:33 +01:00
}
return action, data
2012-09-24 22:17:29 +02:00
def transition_print_(self):
2012-01-02 17:54:33 +01:00
return 'end'
2008-07-17 17:02:17 +02:00
class ThirdPartyBalance(Report):
2012-09-24 22:17:29 +02:00
__name__ = 'account.third_party_balance'
2008-07-17 17:02:17 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def parse(cls, report, objects, data, localcontext):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Party = pool.get('party.party')
MoveLine = pool.get('account.move.line')
2013-09-06 22:33:47 +02:00
Move = pool.get('account.move')
Account = pool.get('account.account')
2012-09-24 22:17:29 +02:00
Company = pool.get('company.company')
Date = pool.get('ir.date')
2010-08-19 22:02:00 +02:00
cursor = Transaction().cursor
2013-09-06 22:33:47 +02:00
line = MoveLine.__table__()
move = Move.__table__()
account = Account.__table__()
2012-09-24 22:17:29 +02:00
company = Company(data['company'])
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['fiscalyear'] = data['fiscalyear']
with Transaction().set_context(context=localcontext):
2013-09-06 22:33:47 +02:00
line_query, _ = MoveLine.query_get(line)
2012-01-02 17:54:33 +01:00
if data['posted']:
2013-09-06 22:33:47 +02:00
posted_clause = move.state == 'posted'
2008-07-17 17:02:17 +02:00
else:
2013-09-06 22:33:47 +02:00
posted_clause = Literal(True)
2008-07-17 17:02:17 +02:00
2013-09-06 22:33:47 +02:00
cursor.execute(*line.join(move, condition=line.move == move.id
).join(account, condition=line.account == account.id
).select(line.party, Sum(line.debit), Sum(line.credit),
where=(line.party != Null)
2013-09-06 22:33:47 +02:00
& account.active
& account.kind.in_(('payable', 'receivable'))
& (account.company == data['company'])
& ((line.maturity_date <= Date.today())
| (line.maturity_date == Null))
2013-09-06 22:33:47 +02:00
& line_query & posted_clause,
group_by=line.party,
having=(Sum(line.debit) != 0) | (Sum(line.credit) != 0)))
2008-07-17 17:02:17 +02:00
res = cursor.fetchall()
id2party = {}
2012-09-24 22:17:29 +02:00
for party in Party.browse([x[0] for x in res]):
id2party[party.id] = party
objects = [{
'name': id2party[x[0]].rec_name,
'debit': x[1],
'credit': x[2],
'solde': x[1] - x[2],
} for x in res]
objects.sort(lambda x, y: cmp(x['name'], y['name']))
2010-08-19 22:02:00 +02:00
localcontext['total_debit'] = sum((x['debit'] for x in objects))
localcontext['total_credit'] = sum((x['credit'] for x in objects))
localcontext['total_solde'] = sum((x['solde'] for x in objects))
2012-09-24 22:17:29 +02:00
return super(ThirdPartyBalance, cls).parse(report, objects, data,
2012-01-02 17:54:33 +01:00
localcontext)
2008-07-17 17:02:17 +02:00
2008-07-22 10:11:28 +02:00
2012-01-02 17:54:33 +01:00
class OpenAgedBalanceStart(ModelView):
'Open Aged Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_aged_balance.start'
2008-07-22 10:11:28 +02:00
company = fields.Many2One('company.company', 'Company', required=True)
balance_type = fields.Selection(
[('customer', 'Customer'), ('supplier', 'Supplier'), ('both', 'Both')],
"Type", required=True)
term1 = fields.Integer("First Term", required=True)
term2 = fields.Integer("Second Term", required=True)
term3 = fields.Integer("Third Term", required=True)
2008-09-15 00:22:24 +02:00
unit = fields.Selection(
2008-07-22 10:11:28 +02:00
[('day', 'Day'), ('month', 'Month')], "Unit", required=True)
2009-03-20 13:49:25 +01:00
posted = fields.Boolean('Posted Move', help='Show only posted move')
2008-07-22 10:11:28 +02:00
2012-09-24 22:17:29 +02:00
@staticmethod
def default_balance_type():
2008-07-22 10:11:28 +02:00
return "customer"
2012-09-24 22:17:29 +02:00
@staticmethod
def default_posted():
2008-07-22 10:11:28 +02:00
return False
2012-09-24 22:17:29 +02:00
@staticmethod
def default_term1():
2008-07-22 10:11:28 +02:00
return 30
2012-09-24 22:17:29 +02:00
@staticmethod
def default_term2():
2008-07-22 10:11:28 +02:00
return 60
2012-09-24 22:17:29 +02:00
@staticmethod
def default_term3():
2008-07-22 10:11:28 +02:00
return 90
2012-09-24 22:17:29 +02:00
@staticmethod
def default_unit():
2008-07-22 10:11:28 +02:00
return 'day'
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-07-22 10:11:28 +02:00
class OpenAgedBalance(Wizard):
'Open Aged Party Balance'
2012-09-24 22:17:29 +02:00
__name__ = 'account.open_aged_balance'
2012-01-02 17:54:33 +01:00
start = StateView('account.open_aged_balance.start',
2012-09-07 13:11:27 +02:00
'account.open_aged_balance_start_view_form', [
2012-01-02 17:54:33 +01:00
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateAction('account.report_aged_balance')
2008-07-22 10:11:28 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def __setup__(cls):
super(OpenAgedBalance, cls).__setup__()
cls._error_messages.update({
2008-07-22 11:57:45 +02:00
'warning': 'Warning',
'term_overlap_desc': 'You cannot define overlapping terms',
})
2008-07-22 11:57:45 +02:00
2012-09-24 22:17:29 +02:00
def do_print_(self, action):
if not (self.start.term1 < self.start.term2 < self.start.term3):
2010-08-19 22:02:00 +02:00
self.raise_user_error(error="warning",
2012-09-24 22:17:29 +02:00
error_description="term_overlap_desc")
2012-01-02 17:54:33 +01:00
data = {
2012-09-24 22:17:29 +02:00
'company': self.start.company.id,
'term1': self.start.term1,
'term2': self.start.term2,
'term3': self.start.term3,
'unit': self.start.unit,
'posted': self.start.posted,
'balance_type': self.start.balance_type,
2012-01-02 17:54:33 +01:00
}
return action, data
2012-09-24 22:17:29 +02:00
def transition_print_(self):
2012-01-02 17:54:33 +01:00
return 'end'
2008-07-22 10:11:28 +02:00
class AgedBalance(Report):
2012-09-24 22:17:29 +02:00
__name__ = 'account.aged_balance'
2008-07-22 10:11:28 +02:00
2012-09-24 22:17:29 +02:00
@classmethod
def parse(cls, report, objects, data, localcontext):
2011-07-03 13:18:40 +02:00
pool = Pool()
2012-09-24 22:17:29 +02:00
Party = pool.get('party.party')
MoveLine = pool.get('account.move.line')
2013-09-06 22:33:47 +02:00
Move = pool.get('account.move')
Account = pool.get('account.account')
2012-09-24 22:17:29 +02:00
Company = pool.get('company.company')
Date = pool.get('ir.date')
2010-08-19 22:02:00 +02:00
cursor = Transaction().cursor
2008-10-08 12:17:47 +02:00
2013-09-06 22:33:47 +02:00
line = MoveLine.__table__()
move = Move.__table__()
account = Account.__table__()
2012-09-24 22:17:29 +02:00
company = Company(data['company'])
2010-08-19 22:02:00 +02:00
localcontext['digits'] = company.currency.digits
2012-01-02 17:54:33 +01:00
localcontext['posted'] = data['posted']
with Transaction().set_context(context=localcontext):
2013-09-06 22:33:47 +02:00
line_query, _ = MoveLine.query_get(line)
2008-07-22 10:11:28 +02:00
2012-01-02 17:54:33 +01:00
terms = (data['term1'], data['term2'], data['term3'])
if data['unit'] == 'month':
coef = datetime.timedelta(days=30)
2008-07-22 10:11:28 +02:00
else:
coef = datetime.timedelta(days=1)
2008-07-22 10:11:28 +02:00
2012-01-02 17:54:33 +01:00
kind = {
'both': ('payable', 'receivable'),
'supplier': ('payable',),
'customer': ('receivable',),
}[data['balance_type']]
2008-07-22 10:11:28 +02:00
res = {}
2012-04-03 20:06:15 +02:00
for position, term in enumerate(terms):
2013-09-06 22:33:47 +02:00
term_query = line.maturity_date <= (Date.today() - term * coef)
if position != 2:
term_query &= line.maturity_date > (
Date.today() - terms[position + 1] * coef)
2008-07-22 10:11:28 +02:00
2013-09-06 22:33:47 +02:00
cursor.execute(*line.join(move, condition=line.move == move.id
).join(account, condition=line.account == account.id
).select(line.party, Sum(line.debit) - Sum(line.credit),
where=(line.party != Null)
2013-09-06 22:33:47 +02:00
& account.active
& account.kind.in_(kind)
& (line.reconciliation == Null)
2013-09-06 22:33:47 +02:00
& (account.company == data['company'])
& term_query & line_query,
group_by=line.party,
having=(Sum(line.debit) - Sum(line.credit)) != 0))
2008-07-22 10:11:28 +02:00
for party, solde in cursor.fetchall():
if party in res:
res[party][position] = solde
else:
2013-02-16 18:54:35 +01:00
res[party] = [(i[0] == position) and solde
or Decimal("0.0") for i in enumerate(terms)]
2012-09-24 22:17:29 +02:00
parties = Party.search([
('id', 'in', [k for k in res.iterkeys()]),
2010-08-19 22:02:00 +02:00
])
2008-07-22 10:11:28 +02:00
2012-01-02 17:54:33 +01:00
localcontext['main_title'] = data['balance_type']
localcontext['unit'] = data['unit']
2008-07-22 11:57:45 +02:00
for i in range(3):
2012-04-03 20:06:15 +02:00
localcontext['total' + str(i)] = sum(
(v[i] for v in res.itervalues()))
2010-08-19 22:02:00 +02:00
localcontext['term' + str(i)] = terms[i]
2008-07-22 11:57:45 +02:00
2010-08-19 22:02:00 +02:00
localcontext['company'] = company
2012-04-03 20:06:15 +02:00
localcontext['parties'] = [{
'name': p.rec_name,
'amount0': res[p.id][0],
'amount1': res[p.id][1],
'amount2': res[p.id][2],
} for p in parties]
2012-09-24 22:17:29 +02:00
return super(AgedBalance, cls).parse(report, objects, data,
2012-01-02 17:54:33 +01:00
localcontext)