1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2011 MSF, TeMPO Consulting.
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU Affero General Public License as
9
# published by the Free Software Foundation, either version 3 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Affero General Public License for more details.
17
# You should have received a copy of the GNU Affero General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
##############################################################################
23
from dateutil.relativedelta import relativedelta
24
from osv import fields, osv
25
from tools.translate import _
26
from lxml import etree
28
class analytic_account(osv.osv):
29
_name = "account.analytic.account"
30
_inherit = "account.analytic.account"
33
'name': fields.char('Name', size=128, required=True),
34
'code': fields.char('Code', size=24),
35
'type': fields.selection([('view','View'), ('normal','Normal')], 'Type', help='If you select the View Type, it means you won\'t allow to create journal entries using that account.'),
36
'date_start': fields.date('Active from', required=True),
37
'date': fields.date('Inactive from', select=True),
38
'category': fields.selection([('OC','Cost Center'),
39
('FUNDING','Funding Pool'),
41
('FREE2','Free 2')], 'Category', select=1),
42
'cost_center_ids': fields.many2many('account.analytic.account', 'funding_pool_associated_cost_centers', 'funding_pool_id', 'cost_center_id', string='Cost Centers'),
43
'account_ids': fields.many2many('account.account', 'funding_pool_associated_accounts', 'funding_pool_id', 'account_id', string='Accounts'),
44
'for_fx_gain_loss': fields.boolean(string="For FX gain/loss", help="Is this account for default FX gain/loss?"),
48
'date_start': lambda *a: (datetime.datetime.today() + relativedelta(months=-3)).strftime('%Y-%m-%d'),
49
'for_fx_gain_loss': lambda *a: False,
51
def _check_unicity(self, cr, uid, ids, context=None):
54
for account in self.browse(cr, uid, ids, context=context):
55
bad_ids = self.search(cr, uid, [('category', '=', account.category),('|'),('name', '=ilike', account.name),('code', '=ilike', account.code)])
56
if len(bad_ids) and len(bad_ids) > 1:
60
def _check_gain_loss_account_unicity(self, cr, uid, ids, context=None):
62
Check that no more account is "for_fx_gain_loss" available.
66
search_ids = self.search(cr, uid, [('for_fx_gain_loss', '=', True)])
67
if search_ids and len(search_ids) > 1:
71
def _check_gain_loss_account_type(self, cr, uid, ids, context=None):
73
Check account type for fx_gain_loss_account: should be Normal type and Cost Center category
77
for account in self.browse(cr, uid, ids, context=context):
78
if account.for_fx_gain_loss == True and (account.type != 'normal' or account.category != 'OC'):
83
(_check_unicity, 'You cannot have the same code or name between analytic accounts in the same category!', ['code', 'name', 'category']),
84
(_check_gain_loss_account_unicity, 'You can only have one account used for FX gain/loss!', ['for_fx_gain_loss']),
85
(_check_gain_loss_account_type, 'You have to use a Normal account type and Cost Center category for FX gain/loss!', ['for_fx_gain_loss']),
88
def copy(self, cr, uid, id, default=None, context=None, done_list=[], local=False):
89
account = self.browse(cr, uid, id, context=context)
92
default = default.copy()
93
default['code'] = (account['code'] or '') + '(copy)'
94
default['name'] = (account['name'] or '') + '(copy)'
95
return super(analytic_account, self).copy(cr, uid, id, default, context=context)
97
def set_funding_pool_parent(self, cr, uid, vals):
98
if 'category' in vals and \
100
vals['category'] == 'FUNDING' and \
101
vals['code'] != 'FUNDING':
102
# for all accounts except the parent one
103
funding_pool_parent = self.search(cr, uid, [('category', '=', 'FUNDING'), ('parent_id', '=', False)])[0]
104
vals['parent_id'] = funding_pool_parent
106
def _check_date(self, vals):
107
if 'date' in vals and vals['date'] is not False:
108
if vals['date'] <= datetime.date.today().strftime('%Y-%m-%d'):
109
# validate the date (must be > today)
110
raise osv.except_osv(_('Warning !'), _('You cannot set an inactivity date lower than tomorrow!'))
111
elif 'date_start' in vals and not vals['date_start'] < vals['date']:
112
# validate that activation date
113
raise osv.except_osv(_('Warning !'), _('Activation date must be lower than inactivation date!'))
115
def create(self, cr, uid, vals, context=None):
117
Some verifications before analytic account creation
119
self._check_date(vals)
120
self.set_funding_pool_parent(cr, uid, vals)
121
return super(analytic_account, self).create(cr, uid, vals, context=context)
123
def write(self, cr, uid, ids, vals, context=None):
125
Some verifications before analytic account write
127
self._check_date(vals)
128
self.set_funding_pool_parent(cr, uid, vals)
129
return super(analytic_account, self).write(cr, uid, ids, vals, context=context)
131
def search(self, cr, uid, args, offset=0, limit=None, order=None,
132
context=None, count=False):
133
if context and 'filter_inactive_accounts' in context and context['filter_inactive_accounts']:
134
args.append(('date_start', '<=', datetime.date.today().strftime('%Y-%m-%d')))
136
args.append(('date', '>', datetime.date.today().strftime('%Y-%m-%d')))
137
args.append(('date', '=', False))
139
if context and 'search_by_ids' in context and context['search_by_ids']:
145
args.append(('id', 'in', ids))
147
return super(analytic_account, self).search(cr, uid, args, offset, limit,
148
order, context=context, count=count)
150
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
153
view = super(analytic_account, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
155
oc_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_project')[1]
158
if view_type=='form':
159
tree = etree.fromstring(view['arch'])
160
fields = tree.xpath('/form/field[@name="cost_center_ids"]')
162
field.set('domain', "[('type', '!=', 'view'), ('id', 'child_of', [%s])]" % oc_id)
163
view['arch'] = etree.tostring(tree)
166
def on_change_category(self, cr, uid, id, category):
169
res = {'value': {}, 'domain': {}}
170
parent = self.search(cr, uid, [('category', '=', category), ('parent_id', '=', False)])[0]
171
res['value']['parent_id'] = parent
172
res['domain']['parent_id'] = [('category', '=', category), ('type', '=', 'view')]
175
def unlink(self, cr, uid, ids, context=None):
177
Delete the dummy analytic account is forbidden!
182
if isinstance(ids, (int, long)):
184
# Prepare some values
185
analytic_accounts = []
186
# Search dummy CC that have xml_id: analytic_account_project_dummy
188
dummy_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_project_dummy')[1]
191
analytic_accounts.append(dummy_id)
194
oc_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_project')[1]
197
analytic_accounts.append(oc_id)
198
# Search Funding Pool
200
fp_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_funding_pool')[1]
203
analytic_accounts.append(fp_id)
206
f1_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_free_1')[1]
209
analytic_accounts.append(f1_id)
212
f2_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_free_2')[1]
215
analytic_accounts.append(f2_id)
216
# Search MSF Private Fund
218
msf_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'analytic_distribution', 'analytic_account_msf_private_funds')[1]
221
analytic_accounts.append(msf_id)
222
# Accounts verification
224
if id in analytic_accounts:
225
raise osv.except_osv(_('Error'), _('You cannot delete this Analytic Account!'))
226
return super(analytic_account, self).unlink(cr, uid, ids, context=context)
229
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: