68
76
arg.append(('inactivation_date', '<=', cmp_date))
79
#@@@override account.account_account.__compute
80
def __compute(self, cr, uid, ids, field_names, arg=None, context=None,
81
query='', query_params=()):
82
""" compute the balance, debit and/or credit for the provided
86
`field_names`: the fields to compute (a list of any of
87
'balance', 'debit' and 'credit')
88
`arg`: unused fields.function stuff
89
`query`: additional query filter (as a string)
90
`query_params`: parameters for the provided query string
91
(__compute will handle their escaping) as a
95
'balance': "COALESCE(SUM(l.debit),0) " \
96
"- COALESCE(SUM(l.credit), 0) as balance",
97
'debit': "COALESCE(SUM(l.debit), 0) as debit",
98
'credit': "COALESCE(SUM(l.credit), 0) as credit"
100
#get all the necessary accounts
101
children_and_consolidated = self._get_children_and_consol(cr, uid, ids, context=context)
102
#compute for each account the balance/debit/credit from the move lines
105
# Add some query/query_params regarding context
107
if context.get('currency_id', False):
110
query += link + 'currency_id = %s'
111
query_params += tuple([context.get('currency_id')])
113
if context.get('instance_ids', False):
116
instance_ids = context.get('instance_ids')
117
if isinstance(instance_ids, (int, long)):
118
instance_ids = [instance_ids]
119
if len(instance_ids) == 1:
120
query += link + 'l.instance_id = %s'
122
query += link + 'l.instance_id in %s'
123
query_params += tuple(instance_ids)
125
if children_and_consolidated:
126
aml_query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
130
wheres.append(query.strip())
131
if aml_query.strip():
132
wheres.append(aml_query.strip())
133
filters = " AND ".join(wheres)
134
# target_move from chart of account wizard
135
filters = filters.replace("AND l.state <> 'draft'", '')
137
if context.get('move_state', False):
138
prefilters += "AND l.move_id = m.id AND m.state = '%s'" % context.get('move_state')
140
prefilters += "AND l.move_id = m.id AND m.state in ('posted', 'draft')"
142
self.logger.notifyChannel('account_override.'+self._name, netsvc.LOG_DEBUG,
143
'Filters: %s'%filters)
144
# IN might not work ideally in case there are too many
145
# children_and_consolidated, in that case join on a
147
# SELECT l.account_id as id FROM account_move_line l
148
# INNER JOIN (VALUES (id1), (id2), (id3), ...) AS tmp (id)
149
# ON l.account_id = tmp.id
150
# or make _get_children_and_consol return a query and join on that
151
request = ("SELECT l.account_id as id, " +\
152
', '.join(map(mapping.__getitem__, field_names)) +
153
" FROM account_move_line l, account_move m" +\
154
" WHERE l.account_id IN %s " \
155
+ prefilters + filters +
156
" GROUP BY l.account_id")
157
params = (tuple(children_and_consolidated),) + query_params
158
cr.execute(request, params)
159
self.logger.notifyChannel('account_override.'+self._name, netsvc.LOG_DEBUG,
160
'Status: %s'%cr.statusmessage)
162
for res in cr.dictfetchall():
163
accounts[res['id']] = res
165
# consolidate accounts with direct children
166
children_and_consolidated.reverse()
167
brs = list(self.browse(cr, uid, children_and_consolidated, context=context))
168
currency_obj = self.pool.get('res.currency')
172
for fn in field_names:
173
sums.setdefault(current.id, {})[fn] = accounts.get(current.id, {}).get(fn, 0.0)
174
for child in current.child_id:
175
if child.company_id.currency_id.id == current.company_id.currency_id.id:
176
sums[current.id][fn] += sums[child.id][fn]
178
sums[current.id][fn] += currency_obj.compute(cr, uid, child.company_id.currency_id.id, current.company_id.currency_id.id, sums[child.id][fn], context=context)
180
null_result = dict((fn, 0.0) for fn in field_names)
181
company_currency = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id.id
183
res[i] = sums.get(i, null_result)
184
# If output_currency_id in context, we change computation
185
for f_name in ('debit', 'credit', 'balance'):
186
if context.get('output_currency_id', False) and res[i].get(f_name, False):
187
new_amount = currency_obj.compute(cr, uid, context.get('output_currency_id'), company_currency, res[i].get(f_name), context=context)
188
res[i][f_name] = new_amount
192
def _get_restricted_area(self, cr, uid, ids, field_name, args, context=None):
200
for account_id in ids:
201
res[account_id] = True
204
def _search_restricted_area(self, cr, uid, ids, name, args, context=None):
206
Search the right domain to apply to this account filter.
207
For this, it uses the "ACCOUNT_RESTRICTED_AREA" variable in which we list all well-known cases.
208
The key args is "restricted_area", the param is like "register_lines".
209
In ACCOUNT_RESTRICTED_AREA, we use the param as key. It so return the domain to apply.
210
If no domain, return an empty domain.
217
if x[0] == 'restricted_area' and x[2]:
218
if x[2] in ACCOUNT_RESTRICTED_AREA:
219
for subdomain in ACCOUNT_RESTRICTED_AREA[x[2]]:
220
arg.append(subdomain)
221
elif x[0] != 'restricted_area':
224
raise osv.except_osv(_('Error'), _('Operation not implemented!'))
227
def _get_fake_cash_domain(self, cr, uid, ids, field_name, arg, context=None):
229
Fake method for domain
238
def _search_cash_domain(self, cr, uid, ids, field_names, args, context=None):
240
Return a given domain (defined in ACCOUNT_RESTRICTED_AREA variable)
246
if x[0] and x[1] == '=' and x[2]:
247
if x[2] in ['cash', 'bank', 'cheque']:
248
arg.append(('restricted_area', '=', 'journals'))
250
raise osv.except_osv(_('Error'), _('Operation not implemented!'))
253
def _get_is_specific_counterpart(self, cr, uid, ids, field_names, args, context=None):
255
If this account is the same as default intermission counterpart OR rebilling intersection account, then return True. Otherwise return nothing.
260
# Prepare some values
263
if field_names == 'is_intermission_counterpart':
264
account = self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart
265
elif field_names == 'is_intersection_counterpart':
266
account = self.pool.get('res.users').browse(cr, uid, uid).company_id.import_invoice_default_account
267
specific_account_id = account and account.id or False
269
for account_id in ids:
270
res[account_id] = False
271
if specific_account_id in ids:
272
res[specific_account_id] = True
275
def _search_is_specific_counterpart(self, cr, uid, ids, field_names, args, context=None):
277
Return the intermission counterpart OR the rebilling intersection account ID.
282
# Prepare some values
286
if field_names == 'is_intermission_counterpart':
287
account = self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart
288
fieldname = 'intermission_default_counterpart'
289
elif field_names == 'is_intersection_counterpart':
290
account = self.pool.get('res.users').browse(cr, uid, uid).company_id.import_invoice_default_account
291
fieldname = 'import_invoice_default_account'
292
specific_account_id = account and account.id or False
295
if x[0] == field_names and x[2] is True:
296
if specific_account_id:
297
arg.append(('id', '=', specific_account_id))
298
elif x[0] == field_names and x[2] is False:
299
if specific_account_id:
300
arg.append(('id', '!=', specific_account_id))
301
elif x[0] != field_names:
304
raise osv.except_osv(_('Error'), _('Filter on field %s not implemented! %s') % (field_names, x,))
72
308
'name': fields.char('Name', size=128, required=True, select=True, translate=True),
73
'type_for_register': fields.selection([('none', 'None'), ('transfer', 'Internal Transfer'), ('transfer_same','Internal Transfer (same currency)'),
309
'activation_date': fields.date('Active from', required=True),
310
'inactivation_date': fields.date('Inactive from'),
311
'note': fields.char('Note', size=160),
312
'type_for_register': fields.selection([('none', 'None'), ('transfer', 'Internal Transfer'), ('transfer_same','Internal Transfer (same currency)'),
74
313
('advance', 'Operational Advance'), ('payroll', 'Third party required - Payroll'), ('down_payment', 'Down payment'), ('donation', 'Donation')], string="Type for specific treatment", required=True,
75
help="""This permit to give a type to this account that impact registers. In fact this will link an account with a type of element
76
that could be attached. For an example make the account to be a transfer type will display only registers to the user in the Cash Register
314
help="""This permit to give a type to this account that impact registers. In fact this will link an account with a type of element
315
that could be attached. For an example make the account to be a transfer type will display only registers to the user in the Cash Register
77
316
when he add a new register line.
79
'is_settled_at_hq': fields.boolean("Settled at HQ"),
318
'shrink_entries_for_hq': fields.boolean("Shrink entries for HQ export", help="Check this attribute if you want to consolidate entries on this account before they are exported to the HQ system."),
80
319
'filter_active': fields.function(_get_active, fnct_search=_search_filter_active, type="boolean", method=True, store=False, string="Show only active accounts",),
320
'restricted_area': fields.function(_get_restricted_area, fnct_search=_search_restricted_area, type='boolean', method=True, string="Is this account allowed?"),
321
'cash_domain': fields.function(_get_fake_cash_domain, fnct_search=_search_cash_domain, method=True, type='boolean', string="Domain used to search account in journals", help="This is only to change domain in journal's creation."),
322
'balance': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Balance', multi='balance'),
323
'debit': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Debit', multi='balance'),
324
'credit': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Credit', multi='balance'),
325
'is_intermission_counterpart': fields.function(_get_is_specific_counterpart, fnct_search=_search_is_specific_counterpart, method=True, type='boolean', string='Is the intermission counterpart account?'),
326
'is_intersection_counterpart': fields.function(_get_is_specific_counterpart, fnct_search=_search_is_specific_counterpart, method=True, type='boolean', string='Is the intersection counterpart account?'),
330
'activation_date': lambda *a: (datetime.datetime.today() + relativedelta(months=-3)).strftime('%Y-%m-%d'),
84
331
'type_for_register': lambda *a: 'none',
85
'is_settled_at_hq': lambda *a: False,
332
'shrink_entries_for_hq': lambda *a: True,
335
# UTP-493: Add a dash between code and account name
336
def name_get(self, cr, uid, ids, context=None):
338
Use "-" instead of " " between name and code for account's default name
342
reads = self.read(cr, uid, ids, ['name', 'code'], context=context)
345
name = record['name']
347
name = record['code'] + ' - '+name
348
res.append((record['id'], name))
351
def _get_parent_of(self, cr, uid, ids, limit=10, context=None):
353
Get all parents from the given accounts.
354
To avoid problem of recursion, set a limit from 1 to 10.
361
if isinstance(ids, (int, long)):
363
if limit < 1 or limit > 10:
364
raise osv.except_osv(_('Error'), _("You're only allowed to use a limit between 1 and 10."))
365
# Prepare some values
366
account_ids = list(ids)
371
AND parent_id IS NOT NULL
372
GROUP BY parent_id"""
373
cr.execute(sql, (tuple(ids),))
376
parent_ids = [x[0] for x in cr.fetchall()]
377
account_ids += parent_ids
380
# Stop the search if we reach limit
384
cr.execute(sql, (tuple(parent_ids),))
387
tmp_res = cr.fetchall()
388
tmp_ids = [x[0] for x in tmp_res]
392
parent_ids = list(tmp_ids)
393
account_ids += tmp_ids
396
def _check_date(self, vals, context=None):
400
if 'inactivation_date' in vals and vals['inactivation_date'] is not False:
401
if vals['inactivation_date'] <= datetime.date.today().strftime('%Y-%m-%d') and not context.get('sync_update_execution', False):
402
# validate the date (must be > today)
403
raise osv.except_osv(_('Warning !'), _('You cannot set an inactivity date lower than tomorrow!'))
404
elif 'activation_date' in vals and not vals['activation_date'] < vals['inactivation_date']:
405
# validate that activation date
406
raise osv.except_osv(_('Warning !'), _('Activation date must be lower than inactivation date!'))
408
def create(self, cr, uid, vals, context=None):
409
self._check_date(vals, context=context)
410
return super(account_account, self).create(cr, uid, vals, context=context)
412
def write(self, cr, uid, ids, vals, context=None):
413
self._check_date(vals, context=context)
414
return super(account_account, self).write(cr, uid, ids, vals, context=context)
416
def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
418
Filtering regarding context
422
if context.get('filter_inactive_accounts'):
423
args.append(('activation_date', '<=', datetime.date.today().strftime('%Y-%m-%d')))
425
args.append(('inactivation_date', '>', datetime.date.today().strftime('%Y-%m-%d')))
426
args.append(('inactivation_date', '=', False))
427
return super(account_account, self).search(cr, uid, args, offset, limit, order, context=context, count=count)
90
431
class account_journal(osv.osv):
432
_name = 'account.journal'
91
433
_inherit = 'account.journal'
93
435
# @@@override account>account.py>account_journal>create_sequence