21
21
##############################################################################
22
22
from osv import fields, osv
24
from datetime import datetime
25
from dateutil.relativedelta import relativedelta
26
24
from tools.translate import _
28
26
class account_model_line(osv.osv):
29
27
_name = "account.model.line"
30
28
_inherit = "account.model.line"
30
def _get_distribution_state(self, cr, uid, ids, name, args, context=None):
32
Get state of distribution:
33
- if compatible with the invoice line, then "valid"
34
- if no distribution, take a tour of invoice distribution, if compatible, then "valid"
35
- if no distribution on invoice line and invoice, then "none"
36
- all other case are "invalid"
41
if isinstance(ids, (int, long)):
45
# Browse all given lines
46
for line in self.browse(cr, uid, ids, context=context):
47
res[line.id] = self.pool.get('analytic.distribution')._get_distribution_state(cr, uid, line.analytic_distribution_id.id, line.model_id.analytic_distribution_id.id, line.account_id.id)
50
def _have_analytic_distribution_from_header(self, cr, uid, ids, name, arg, context=None):
52
If model has an analytic distribution, return False, else return True
57
if isinstance(ids, (int, long)):
60
for model in self.browse(cr, uid, ids, context=context):
62
if model.analytic_distribution_id:
66
def _get_is_allocatable(self, cr, uid, ids, name, arg, context=None):
68
If analytic-a-holic account, then this account is allocatable.
70
if isinstance(ids, (int, long)):
73
for model_line in self.browse(cr, uid, ids):
74
res[model_line.id] = True
75
if model_line.account_id and not model_line.account_id.is_analytic_addicted:
76
res[model_line.id] = False
79
def _get_distribution_state_recap(self, cr, uid, ids, name, arg, context=None):
81
Get a recap from analytic distribution state and if it come from header or not.
83
if isinstance(ids, (int, long)):
86
for model_line in self.browse(cr, uid, ids):
87
res[model_line.id] = ''
88
if not model_line.is_allocatable:
91
if model_line.have_analytic_distribution_from_header:
92
from_header = _(' (from header)')
93
ana_distri_state = self.pool.get('ir.model.fields').get_browse_selection(cr, uid, model_line, 'analytic_distribution_state', context)
94
res[model_line.id] = "%s%s" % (ana_distri_state, from_header)
97
def _get_exp_in_line_state(self, cr, uid, ids, name, args, context=None):
101
if isinstance(ids, (int, long)):
103
for line in self.browse(cr, uid, ids, context=context):
104
if line.account_id.user_type.code in ('expense', 'income'):
105
if line.have_analytic_distribution_from_header \
106
and not line.model_id.analytic_distribution_id:
108
res[line.id] = 'no_header'
111
res[line.id] = line.analytic_distribution_state
113
res[line.id] = 'no_exp_in'
117
'analytic_distribution_state': fields.function(_get_distribution_state, method=True, type='selection',
118
selection=[('none', 'None'), ('valid', 'Valid'), ('invalid', 'Invalid')],
119
string="Distribution state", help="Informs from distribution state among 'none', 'valid', 'invalid."),
120
'have_analytic_distribution_from_header': fields.function(_have_analytic_distribution_from_header, method=True, type='boolean',
121
string='Header Distrib.?'),
122
'is_allocatable': fields.function(_get_is_allocatable, method=True, type='boolean', string="Is allocatable?", readonly=True, store=False),
123
'analytic_distribution_state_recap': fields.function(_get_distribution_state_recap, method=True, type='char', size=30,
124
string="Distribution",
125
help="Informs you about analaytic distribution state among 'none', 'valid', 'invalid', from header or not, or no analytic distribution"),
126
'sequence': fields.integer('Sequence', readonly=True, help="The sequence field is used to order the resources from lower sequences to higher ones"),
33
127
'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
34
'account_user_type_code': fields.related('account_id', 'user_type_code', type="char", string="Account User Type Code", store=False)
128
'exp_in_ad_state': fields.function(_get_exp_in_line_state, method=True, type='selection',
129
selection=[('no_exp_in', 'Not expense/income'), ('no_header', 'No header'), ('valid', 'Valid'), ('invalid', 'Invalid')],
130
string='Expense/income line status'), # UFTP-103
134
'have_analytic_distribution_from_header': lambda *a: True,
135
'is_allocatable': lambda *a: True,
136
'analytic_distribution_state_recap': lambda *a: '',
139
def create(self, cr, uid, vals, context=None):
140
model = self.pool.get('account.model').browse(cr, uid, vals['model_id'], context=context)
141
# just add the next line
142
vals['sequence'] = len(model.lines_id) + 1
143
return super(account_model_line, self).create(cr, uid, vals, context=context)
37
145
def button_analytic_distribution(self, cr, uid, ids, context=None):
39
147
Launch analytic distribution wizard on an invoice line
80
188
'res_id': [wiz_id],
81
189
'context': context,
192
def copy_data(self, cr, uid, id, default=None, context=None):
194
Copy global distribution and give it to new model line
201
# Copy analytic distribution
202
model_line = self.browse(cr, uid, [id], context=context)[0]
203
if model_line.analytic_distribution_id:
204
new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, model_line.analytic_distribution_id.id, {}, context=context)
206
default.update({'analytic_distribution_id': new_distrib_id})
207
return super(account_model_line, self).copy_data(cr, uid, id, default, context)
84
209
account_model_line()
86
211
class account_model(osv.osv):
87
212
_name = "account.model"
88
213
_inherit = "account.model"
215
def _has_any_bad_ad_line_exp_in(self, cr, uid, ids, name, args, context=None):
219
if isinstance(ids, (int, long)):
221
for model in self.browse(cr, uid, ids, context=context):
222
res[model.id] = False
223
for line in model.lines_id:
224
if line.exp_in_ad_state and line.exp_in_ad_state in ('no_header', 'invalid'):
230
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
231
'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
232
'has_any_bad_ad_line_exp_in': fields.function(_has_any_bad_ad_line_exp_in,
233
method=True, type='boolean',
234
string='Has bad analytic distribution on expense/income lines',
235
help='There is lines with expense or income accounts with invalid analytic distribution or using header AD that is not defined or not compatible.'), # UFTP-103
239
'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id,
240
'has_any_bad_ad_line_exp_in': False,
90
243
# @@@override@account.account_model.generate()
91
244
def generate(self, cr, uid, ids, datas={}, context=None):
122
279
'journal_id': model.journal_id.id,
123
280
'period_id': period_id,
125
if line.account_id.user_type_code == 'expense':
126
if not line.analytic_distribution_id:
127
raise osv.except_osv(_('No Analytic Distribution !'),_("You have to define an analytic distribution on the '%s' line!") % (line.name))
282
if line.account_id.is_analytic_addicted:
283
if line.analytic_distribution_state == 'invalid':
284
raise osv.except_osv(_('Invalid Analytic Distribution !'),_("Please define a valid analytic distribution for the recurring model '%s'!") % (line.name))
128
285
if not model.journal_id.analytic_journal_id:
129
286
raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
130
new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
131
val.update({'analytic_distribution_id': new_distribution_id})
287
if line.analytic_distribution_id:
288
new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
289
val.update({'analytic_distribution_id': new_distribution_id})
290
elif model.analytic_distribution_id:
291
new_distribution_id = ana_obj.copy(cr, uid, model.analytic_distribution_id.id, {}, context=context)
292
val.update({'analytic_distribution_id': new_distribution_id})
133
294
date_maturity = time.strftime('%Y-%m-%d')
134
295
if line.date_maturity == 'partner':
135
296
if not line.partner_id:
327
def button_analytic_distribution(self, cr, uid, ids, context=None):
329
Launch analytic distribution wizard on a model
334
if isinstance(ids, (int, long)):
336
# Prepare some values
337
model = self.browse(cr, uid, ids[0], context=context)
339
# Search elements for currency
340
company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
341
currency = model.currency_id and model.currency_id.id or company_currency
342
for line in model.lines_id:
343
amount += (line.debit - line.credit)
345
# Get analytic_distribution_id
346
distrib_id = model.analytic_distribution_id and model.analytic_distribution_id.id
347
# Prepare values for wizard
349
'total_amount': amount,
350
'model_id': model.id,
351
'currency_id': currency or False,
355
vals.update({'distribution_id': distrib_id,})
357
wiz_obj = self.pool.get('analytic.distribution.wizard')
358
wiz_id = wiz_obj.create(cr, uid, vals, context=context)
359
# Update some context values
366
'name': _('Global analytic distribution'),
367
'type': 'ir.actions.act_window',
368
'res_model': 'analytic.distribution.wizard',
376
def button_reset_distribution(self, cr, uid, ids, context=None):
378
Reset analytic distribution on all recurring lines.
379
To do this, just delete the analytic_distribution id link on each recurring line.
383
if isinstance(ids, (int, long)):
385
# Prepare some values
386
recurring_obj = self.pool.get(self._name + '.line')
387
# Search recurring lines
388
to_reset = recurring_obj.search(cr, uid, [('model_id', 'in', ids)])
389
recurring_obj.write(cr, uid, to_reset, {'analytic_distribution_id': False})
165
393
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: