20
20
##############################################################################
22
22
from osv import fields, osv
24
from dateutil.relativedelta import relativedelta
24
# Overloading the one2many.get for budget lines to filter regarding context.
26
# Overloading the one2many.get for budget lines
27
# (used for filtering budget lines in the form view;
28
# dirty as f*ck, but hey, it works)
25
29
class one2many_budget_lines(fields.one2many):
27
31
def get(self, cr, obj, ids, name, uid=None, offset=0, context=None, values=None):
29
Use 'granularity' value in context to filter budget lines.
30
If granularity is 'view', then display only budget line that have line_type = view
31
If 'expense', display budget lines that have line_type = view and normal
32
If 'all' display budget lines that are view, normal and destination line_type
33
Else, display view, normal and destination line_type ones.
35
NB: This context also permit "Budget vs. Actual" report to work and display right lines regarding a given granularity.
37
32
if context is None:
44
domain = ['view', 'normal', 'destination']
47
'expense': ['view', 'normal'],
50
line_obj = obj.pool.get('msf.budget.line')
52
if 'granularity' in context:
53
display_type = context.get('granularity', False)
54
if display_type and display_type in ['view', 'expense', 'all']:
55
domain = tuples[display_type]
58
res[budget_id] = line_obj.search(cr, uid, [('budget_id', '=', budget_id), ('line_type', 'in', domain)])
39
for budget in obj.read(cr, uid, ids, ['display_type']):
40
res[budget['id']] = []
41
display_type[budget['id']] = budget['display_type']
43
budget_line_obj = obj.pool.get('msf.budget.line')
44
budget_line_ids = budget_line_obj.search(cr, uid, [('budget_id', 'in', ids)])
46
for budget_line in budget_line_obj.read(cr, uid, budget_line_ids, ['line_type', 'budget_id'], context=context):
47
budget_id = budget_line['budget_id'][0]
48
if display_type[budget_id] == 'all' \
49
or (display_type[budget_id] == 'view' and budget_line['line_type'] == 'view') \
50
or (display_type[budget_id] == 'expense' and budget_line['line_type'] != 'destination'):
51
res[budget_id].append(budget_line['id'])
62
54
class msf_budget_line(osv.osv):
63
55
_name = "msf.budget.line"
64
_order = "account_order, destination_id DESC, id"
57
def _get_actual_amounts(self, cr, uid, ids, context=None):
58
# Input: list of budget lines
59
# Output: a dict of list {general_account_id: [jan_actual, feb_actual,...]}
64
engagement_journal_ids = self.pool.get('account.analytic.journal').search(cr, uid, [('type', '=', 'engagement')], context=context)
66
# we discard the ids, but retrieve the budget from it
67
# Otherwise, view lines don't have values in "view lines only" display mode
70
budget = self.browse(cr, uid, ids[0], context=context).budget_id
71
output_currency_id = budget.currency_id.id
73
cost_center_ids = self.pool.get('msf.budget.tools')._get_cost_center_ids(budget.cost_center_id)
75
# Create search domain (one search for all analytic lines)
76
actual_domain = [('cost_center_id', 'in', cost_center_ids)]
77
actual_domain.append(('date', '>=', budget.fiscalyear_id.date_start))
78
actual_domain.append(('date', '<=', budget.fiscalyear_id.date_stop))
80
# if commitments are set to False in context, the engagement analytic journals are removed
82
if 'commitment' in context and not context['commitment'] and len(engagement_journal_ids) > 0:
83
actual_domain.append(('journal_id', 'in', engagement_journal_ids))
85
# Call budget_tools method
86
res = self.pool.get('msf.budget.tools')._get_actual_amounts(cr, uid, output_currency_id, actual_domain, context=context)
90
def _get_budget_amounts(self, cr, uid, ids, context=None):
91
# Input: list of budget lines
92
# Output: a dict of list {general_account_id: [jan_budget, feb_budget,...]}
98
budget = self.browse(cr, uid, ids[0], context=context).budget_id
100
if budget.type == 'normal':
101
# Budget values are stored in lines; just retrieve and add them
102
for budget_line in self.browse(cr, uid, ids, context=context):
103
budget_line_destination_id = budget_line.destination_id and budget_line.destination_id.id or False
104
if budget_line.budget_values:
105
res[budget_line.account_id.id, budget_line_destination_id] = eval(budget_line.budget_values)
107
res[budget_line.account_id.id, budget_line_destination_id] = [0] * 12
110
for budget_line in self.browse(cr, uid, ids, context=context):
111
budget_line_destination_id = budget_line.destination_id and budget_line.destination_id.id or False
112
res[budget_line.account_id.id, budget_line_destination_id] = [0] * 12
113
# Not stored in lines; retrieve child budgets, get their budget values and add
114
cost_center_list = self.pool.get('msf.budget.tools')._get_cost_center_ids(budget.cost_center_id)
115
# For each cost center, get the latest non-draft budget
116
for cost_center_id in cost_center_list:
117
cr.execute("SELECT id FROM msf_budget WHERE fiscalyear_id = %s \
118
AND cost_center_id = %s \
119
AND decision_moment_id = %s \
120
AND state != 'draft' \
121
AND type = 'normal' \
122
ORDER BY version DESC LIMIT 1",
123
(budget.fiscalyear_id.id,
125
budget.decision_moment_id.id))
127
# A budget was found; get its lines and their amounts
128
child_budget_id = cr.fetchall()[0][0]
129
child_line_ids = self.search(cr,
131
[('budget_id', '=', child_budget_id)],
133
child_budget_amounts = self._get_budget_amounts(cr, uid, child_line_ids, context=context)
134
for child_line in self.browse(cr, uid, child_line_ids, context=context):
135
child_line_destination_id = child_line.destination_id and child_line.destination_id.id or False
136
if (child_line.account_id.id, child_line_destination_id) not in res:
137
res[child_line.account_id.id, child_line_destination_id] = child_budget_amounts[child_line.account_id.id, child_line_destination_id]
139
res[child_line.account_id.id, child_line_destination_id] = [sum(pair) for pair in
140
zip(child_budget_amounts[child_line.account_id.id, child_line_destination_id],
141
res[child_line.account_id.id, child_line_destination_id])]
145
def _compute_total_amounts(self, cr, uid, budget_amount_list, actual_amount_list, context=None):
152
if 'period_id' in context:
153
period = self.pool.get('account.period').browse(cr, uid, context['period_id'], context=context)
154
month_stop = datetime.datetime.strptime(period.date_stop, '%Y-%m-%d').month
158
if actual_amount_list:
159
for i in range(month_stop):
160
actual_amount += actual_amount_list[i]
162
if budget_amount_list:
163
for i in range(month_stop):
164
budget_amount += budget_amount_list[i]
166
return {'actual_amount': actual_amount,
167
'budget_amount': budget_amount}
169
def _get_total_amounts(self, cr, uid, ids, field_names=None, arg=None, context=None):
174
actual_amounts = self._get_actual_amounts(cr, uid, ids, context)
175
budget_amounts = self._get_budget_amounts(cr, uid, ids, context)
178
for budget_line in self.browse(cr, uid, ids, context=context):
179
budget_line_destination_id = budget_line.destination_id and budget_line.destination_id.id or False
180
line_amounts = self._compute_total_amounts(cr,
182
budget_amounts[budget_line.account_id.id, budget_line_destination_id],
183
actual_amounts[budget_line.account_id.id, budget_line_destination_id],
185
actual_amount = line_amounts['actual_amount']
186
budget_amount = line_amounts['budget_amount']
188
# We have budget amount and actual amount, compute the remaining ones
190
if budget_amount != 0.0:
191
percentage = round((actual_amount / budget_amount) * 100.0)
192
res[budget_line.id] = {'budget_amount': budget_amount,
193
'actual_amount': actual_amount,
194
'balance': budget_amount - actual_amount,
195
'percentage': percentage}
199
def _get_monthly_amounts(self, cr, uid, ids, context=None):
204
actual_amounts = self._get_actual_amounts(cr, uid, ids, context)
205
budget_amounts = self._get_budget_amounts(cr, uid, ids, context)
207
# if period id, only retrieve a subset
209
if 'period_id' in context:
210
period = self.pool.get('account.period').browse(cr, uid, context['period_id'], context=context)
211
month_stop = datetime.datetime.strptime(period.date_stop, '%Y-%m-%d').month
216
for budget_line in self.browse(cr, uid, ids, context=context):
217
budget_line_destination_id = budget_line.destination_id and budget_line.destination_id.id or False
218
if budget_line.line_type == 'view' \
219
or ('granularity' in context and context['granularity'] == 'all') \
220
or ('granularity' in context and context['granularity'] == 'expense' and budget_line.line_type != 'destination'):
221
line_actual_amounts = actual_amounts[budget_line.account_id.id, budget_line_destination_id]
222
line_budget_amounts = budget_amounts[budget_line.account_id.id, budget_line_destination_id]
224
line_name = budget_line.account_id.code
225
if budget_line.destination_id:
226
line_name += " " + budget_line.destination_id.code
227
line_name += " " + budget_line.account_id.name
228
line_values = [line_name]
229
if 'breakdown' in context and context['breakdown'] == 'month':
230
# Need to add breakdown values
231
for i in range(month_stop):
233
line_values.append(line_budget_amounts[i])
234
line_values.append(line_actual_amounts[i])
236
total_amounts = self._compute_total_amounts(cr,
241
line_values.append(total_amounts['budget_amount'])
242
line_values.append(total_amounts['actual_amount'])
244
res.append(line_values)
65
248
def _get_name(self, cr, uid, ids, field_names=None, arg=None, context=None):
66
249
result = self.browse(cr, uid, ids, context=context)
69
252
account = rs.account_id
71
254
if rs.destination_id:
73
256
name += rs.destination_id.code
75
258
name += account.name
79
def _get_month_names(self, number=12):
81
Return a list of all month field to be used from the first one to the given number (included).
84
# Do not permit to give a number superior to 12!
87
for x in xrange(1, number+1, 1):
88
res.append('month' + str(x))
91
def _get_domain(self, line_type, account_id, cost_center_ids, destination_id, date_start, date_stop):
93
Create a domain regarding budget line elements (to be used in a search()).
96
if isinstance(cost_center_ids, (int, long)):
97
cost_center_ids = [cost_center_ids]
99
('cost_center_id', 'in', cost_center_ids),
100
('date', '>=', date_start),
101
('date', '<=', date_stop),
103
if line_type == 'destination':
104
res.append(('destination_id', '=', destination_id))
105
if line_type in ['destination', 'normal']:
106
res.append(('general_account_id', '=', account_id)),
108
res.append(('general_account_id', 'child_of', account_id))
111
def _get_sql_domain(self, cr, uid, request, params, line_type, account_id, destination_id):
113
Create a SQL domain regarding budget line elements (to be used in a SQL request).
122
if line_type == 'destination':
123
request += """ AND destination_id = %s """
124
params.append(destination_id)
125
if line_type in ['destination', 'normal']:
126
request += """ AND general_account_id = %s """
127
params.append(account_id)
129
request += """ AND general_account_id IN %s """
130
account_ids = self.pool.get('account.account').search(cr, uid, [('parent_id', 'child_of', account_id)])
131
params.append(tuple(account_ids))
132
return request, params
134
def _get_account_order(self, cr, uid, ids, field_names=None, arg=None, context=None):
136
account_obj = self.pool.get('account.account')
137
if isinstance(ids, (int, long)):
140
for line in self.read(cr, uid, ids, ['account_id'], context=context):
141
account_id = line['account_id'] and line['account_id'][0]
143
if account_id not in seen:
144
acc = account_obj.read(cr, uid, account_id, ['parent_left'])
145
seen[account_id] = acc['parent_left']
146
ret[line['id']] = seen[account_id]
151
def _get_amounts(self, cr, uid, ids, field_names=None, arg=None, context=None):
153
Those field can be asked for:
159
- percentage needs actual_amount, comm_amount, balance and budget_amount
160
- balance needs actual_amount, comm_amount and budget_amount
163
- if 'period_id' in context, we change date_stop for SQL request to the date_stop of the given period to reduce computation
164
- if 'currency_table_id' in context, we compute actual amounts (and commitment ones) currency by currency
169
if isinstance(ids, (int, long)):
171
# Prepare some values
175
commitment_ok = False
176
percentage_ok = False
181
cur_obj = self.pool.get('res.currency')
182
# If period_id in context, use another date_stop element.
183
date_period_stop = False
185
if 'period_id' in context:
186
period = self.pool.get('account.period').read(cr, uid, context.get('period_id', False), ['date_stop', 'number'], context=context)
187
if period and period.get('date_stop', False):
188
date_period_stop = period.get('date_stop')
189
if period and period.get('number', False):
190
month_number = period.get('number')
191
# Check if we need to use another currency_table_id
192
other_currencies = False
194
company_currency_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
195
if context.get('currency_table_id', False):
196
other_currencies = True
197
date_context.update({'currency_table_id': context.get('currency_table_id')})
198
# Check in which case we are regarding field names. Compute actual and commitment when we need balance and/or percentage.
199
if 'budget_amount' in field_names:
201
if 'actual_amount' in field_names:
203
if 'comm_amount' in field_names:
206
if 'percentage' in field_names:
210
if 'balance' in field_names:
214
# In some cases (reports) we don't want to display commitment values. But we have to include them into "balance" and percentage computation.
215
if 'commitment' in context:
216
commitment_ok = context.get('commitment', False)
217
# Compute actual and/or commitments
218
if actual_ok or commitment_ok or percentage_ok or balance_ok:
219
# COMPUTE ACTUAL/COMMITMENT
220
ana_obj = self.pool.get('account.analytic.line')
221
ana_account_obj = self.pool.get('account.analytic.account')
222
cur_obj = self.pool.get('res.currency')
223
# Create default values
226
actual_amounts.setdefault(index, 0.0)
228
comm_amounts.setdefault(index, 0.0)
229
# Now, only use 'destination' line to do process and complete parent one at the same time
231
SELECT l.id, l.line_type, l.account_id, l.destination_id, b.cost_center_id, f.date_start, f.date_stop
232
FROM msf_budget_line AS l, msf_budget AS b, account_fiscalyear AS f
233
WHERE l.budget_id = b.id
234
AND b.fiscalyear_id = f.id
236
ORDER BY l.line_type, l.id"""
237
cr.execute(sql, (tuple(ids),))
238
# Prepare SQL2 request that contains sum of amount of given analytic lines (in functional currency)
241
FROM account_analytic_line
243
# Prepare SQL3 request in case we have other currencies to compute
245
SELECT l.currency_id, SUM(l.amount_currency)
246
FROM account_analytic_line AS l, account_analytic_journal AS j
247
WHERE l.journal_id = j.id
248
AND l.cost_center_id IN %s
251
sql3_end = """ GROUP BY l.currency_id"""
252
# Process destination lines
253
for line in cr.fetchall():
255
line_id, line_type, account_id, destination_id, cost_center_id, date_start, date_stop = line
256
cost_center_ids = ana_account_obj.search(cr, uid, [('parent_id', 'child_of', cost_center_id)])
258
date_stop = date_period_stop
259
criteria = self._get_domain(line_type, account_id, cost_center_ids, destination_id, date_start, date_stop)
260
# TWO METHODS to display actual/commitments
261
# (1) Either we use functional amounts (no currency_table)
262
# (2) Or we use a currency table to change amounts to functional amounts at fiscalyear date_stop
263
if not other_currencies:
264
# (1) Use functional amounts: NO conversion
265
# fill in ACTUAL AMOUNTS
267
actual_criteria = list(criteria) + [('journal_id.type', '!=', 'engagement')]
268
ana_ids = ana_obj.search(cr, uid, actual_criteria)
270
cr.execute(sql2, (tuple(ana_ids),))
271
mnt_result = cr.fetchall()
273
actual_amounts[line_id] += mnt_result[0][0] * -1
274
# fill in COMMITMENT AMOUNTS
276
commitment_criteria = list(criteria) + [('journal_id.type', '=', 'engagement')]
277
ana_ids = ana_obj.search(cr, uid, commitment_criteria)
279
cr.execute(sql2, (tuple(ana_ids),))
280
mnt_result = cr.fetchall()
282
comm_amounts[line_id] += mnt_result[0][0] * -1
284
# (2) OTHER CURRENCIES to compute
285
# Note that to not compute each analytic lines we use the sum of each currency and convert it to the functional currency using the given currency_table_id in the context
286
tmp_sql_params = [tuple(cost_center_ids), date_start, date_stop]
287
tmp_sql, sql_params = self._get_sql_domain(cr, uid, sql3, tmp_sql_params, line_type, account_id, destination_id)
288
# Use fiscalyear end date as date on which we do conversion
289
date_context.update({'date': date_stop})
291
def get_amounts_and_compute_total(local_request, local_params, local_end_request):
294
Finish it with local_end_request.
297
Compute them by currency.
301
if local_end_request:
302
local_request += local_end_request
303
cr.execute(local_request, tuple(local_params))
305
analytic_amounts = cr.fetchall()
306
# Browse each currency amount and convert it to the functional currency (company one)
307
for currency_id, amount in analytic_amounts:
308
tmp_amount = cur_obj.compute(cr, uid, currency_id, company_currency_id, amount, round=False, context=date_context)
309
total += (tmp_amount * -1) # As analytic amounts are negative, we should use the opposite to make budget with positive values
313
actual_sql = tmp_sql + """ AND j.type != 'engagement' """
314
actual_amounts[line_id] += get_amounts_and_compute_total(actual_sql, sql_params, sql3_end)
316
commitment_sql = tmp_sql + """ AND j.type = 'engagement' """
317
comm_amounts[line_id] += get_amounts_and_compute_total(commitment_sql, sql_params, sql3_end)
318
# Budget line amounts
320
month_names = self._get_month_names(month_number)
322
SELECT id, COALESCE(""" + '+'.join(month_names) + """, 0.0)
326
cr.execute(sql, (tuple(ids),))
327
tmp_res = cr.fetchall()
329
budget_amounts = dict(tmp_res)
332
actual_amount = line_id in actual_amounts and actual_amounts[line_id] or 0.0
333
comm_amount = line_id in comm_amounts and comm_amounts[line_id] or 0.0
334
res[line_id] = {'actual_amount': actual_amount, 'comm_amount': comm_amount, 'balance': 0.0, 'percentage': 0.0, 'budget_amount': 0.0,}
336
budget_amount = line_id in budget_amounts and budget_amounts[line_id] or 0.0
337
res[line_id].update({'budget_amount': budget_amount,})
339
balance = budget_amount - actual_amount
341
balance -= comm_amount
342
res[line_id].update({'balance': balance,})
344
if budget_amount != 0.0:
348
percentage = round(base / budget_amount * 100.0)
349
res[line_id].update({'percentage': percentage,})
352
def _get_total(self, cr, uid, ids, field_names=None, arg=None, context=None):
354
Give the sum of all month for the given budget lines.
355
If period_id in context, just display months from the first one to the given period month (included)
358
if isinstance(ids,(int, long)):
361
if 'period_id' in context:
362
period = self.pool.get('account.period').read(cr, uid, context.get('period_id', False), ['number'])
363
if period and period.get('number', False):
364
month_number = period.get('number')
365
month_names = self._get_month_names(month_number)
366
# Prepare some values
369
SELECT id, COALESCE(""" + '+'.join(month_names) + """, 0.0)
372
cr.execute(sql, (tuple(ids),))
373
tmp_res = cr.fetchall()
379
263
'budget_id': fields.many2one('msf.budget', 'Budget', ondelete='cascade'),
380
264
'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type', '!=', 'view')]),
381
265
'destination_id': fields.many2one('account.analytic.account', 'Destination', domain=[('category', '=', 'DEST')]),
382
'name': fields.function(_get_name, method=True, store=False, string="Name", type="char", readonly="True", size=512),
383
'month1': fields.float("Month 01"),
384
'month2': fields.float("Month 02"),
385
'month3': fields.float("Month 03"),
386
'month4': fields.float("Month 04"),
387
'month5': fields.float("Month 05"),
388
'month6': fields.float("Month 06"),
389
'month7': fields.float("Month 07"),
390
'month8': fields.float("Month 08"),
391
'month9': fields.float("Month 09"),
392
'month10': fields.float("Month 10"),
393
'month11': fields.float("Month 11"),
394
'month12': fields.float("Month 12"),
395
'total': fields.function(_get_total, method=True, store=False, string="Total", type="float", readonly=True, help="Get all month total amount"),
396
'budget_amount': fields.function(_get_amounts, method=True, store=False, string="Budget amount", type="float", readonly=True, multi="budget_amounts"),
397
'actual_amount': fields.function(_get_amounts, method=True, store=False, string="Actual amount", type="float", readonly=True, multi="budget_amounts"),
398
'comm_amount': fields.function(_get_amounts, method=True, store=False, string="Commitments amount", type="float", readonly=True, multi="budget_amounts"),
399
'balance': fields.function(_get_amounts, method=True, store=False, string="Balance", type="float", readonly=True, multi="budget_amounts"),
400
'percentage': fields.function(_get_amounts, method=True, store=False, string="Percentage", type="float", readonly=True, multi="budget_amounts"),
266
'name': fields.function(_get_name, method=True, store=False, string="Name", type="char", readonly="True"),
267
'budget_values': fields.char('Budget Values (list of float to evaluate)', size=256),
268
'budget_amount': fields.function(_get_total_amounts, method=True, store=False, string="Budget amount", type="float", readonly="True", multi="all"),
269
'actual_amount': fields.function(_get_total_amounts, method=True, store=False, string="Actual amount", type="float", readonly="True", multi="all"),
270
'balance': fields.function(_get_total_amounts, method=True, store=False, string="Balance", type="float", readonly="True", multi="all"),
271
'percentage': fields.function(_get_total_amounts, method=True, store=False, string="Percentage", type="float", readonly="True", multi="all"),
401
272
'parent_id': fields.many2one('msf.budget.line', 'Parent Line'),
402
273
'child_ids': fields.one2many('msf.budget.line', 'parent_id', 'Child Lines'),
403
274
'line_type': fields.selection([('view','View'),
404
275
('normal','Normal'),
405
276
('destination', 'Destination')], 'Line type', required=True),
406
'account_code': fields.related('account_id', 'code', type='char', string='Account code', size=64, store=True),
407
'account_order': fields.function(_get_account_order, type='integer', string='order', method=True, store=True),
412
'line_type': lambda *a: 'normal',
413
'month1': lambda *a: 0.0,
414
'month2': lambda *a: 0.0,
415
'month3': lambda *a: 0.0,
416
'month4': lambda *a: 0.0,
417
'month5': lambda *a: 0.0,
418
'month6': lambda *a: 0.0,
419
'month7': lambda *a: 0.0,
420
'month8': lambda *a: 0.0,
421
'month9': lambda *a: 0.0,
422
'month10': lambda *a: 0.0,
423
'month11': lambda *a: 0.0,
424
'month12': lambda *a: 0.0,
280
'line_type': 'normal',
283
def get_parent_line(self, cr, uid, vals, context=None):
284
# Method to check if the used account has a parent,
285
# and retrieve or create the corresponding parent line.
286
# It also adds budget values to parent lines
287
parent_account_id = False
289
if 'account_id' in vals and 'budget_id' in vals:
290
if 'destination_id' in vals:
291
# Special case: the line has a destination, so the parent is a line
292
# with the same account and no destination
293
parent_account_id = vals['account_id']
294
parent_line_ids = self.search(cr, uid, [('account_id', '=', vals['account_id']),
295
('budget_id', '=', vals['budget_id']),
296
('line_type', '=', 'normal')], context=context)
298
# search for budget line
299
account = self.pool.get('account.account').browse(cr, uid, vals['account_id'], context=context)
300
chart_of_account_ids = self.pool.get('account.account').search(cr, uid, [('code', '=', 'MSF')], context=context)
301
if account.parent_id and account.parent_id.id in chart_of_account_ids:
302
# no need to create the parent
305
parent_account_id = account.parent_id.id
306
parent_line_ids = self.search(cr, uid, [('account_id', '=', parent_account_id),
307
('budget_id', '=', vals['budget_id'])], context=context)
308
if len(parent_line_ids) > 0:
310
if 'budget_values' in vals:
311
# we add the budget values to the parent one
312
parent_line = self.browse(cr, uid, parent_line_ids[0], context=context)
313
parent_budget_values = [sum(pair) for pair in zip(eval(parent_line.budget_values),
314
eval(vals['budget_values']))]
316
super(msf_budget_line, self).write(cr,
319
{'budget_values': str(parent_budget_values)},
321
# use method on parent with original budget values
322
self.get_parent_line(cr,
324
{'account_id': parent_line.account_id.id,
325
'budget_id': parent_line.budget_id.id,
326
'budget_values': vals['budget_values']},
328
# add parent id to vals
329
vals.update({'parent_id': parent_line_ids[0]})
331
# Create parent line and add it to vals, except if it's the main parent
332
parent_vals = {'budget_id': vals['budget_id'],
333
'account_id': parent_account_id}
334
if 'line_type' in vals and vals['line_type'] == 'destination':
335
parent_vals['line_type'] = 'normal'
337
parent_vals['line_type'] = 'view'
338
# default parent budget values: the one from the (currently) only child
339
if 'budget_values' in vals:
340
parent_vals.update({'budget_values': vals['budget_values']})
341
parent_budget_line_id = self.create(cr, uid, parent_vals, context=context)
342
vals.update({'parent_id': parent_budget_line_id})
346
def create(self, cr, uid, vals, context=None):
347
self.get_parent_line(cr, uid, vals, context=context)
348
return super(msf_budget_line, self).create(cr, uid, vals, context=context)
350
def write(self, cr, uid, ids, vals, context=None):
351
self.get_parent_line(cr, uid, vals, context=context)
352
return super(msf_budget_line, self).write(cr, uid, ids, vals, context=context)
427
354
msf_budget_line()
429
356
class msf_budget(osv.osv):
430
357
_name = "msf.budget"
431
358
_inherit = "msf.budget"
434
361
'budget_line_ids': one2many_budget_lines('msf.budget.line', 'budget_id', 'Budget Lines'),
438
365
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: