2
# -*- coding: utf-8 -*-
3
##############################################################################
5
# OpenERP, Open Source Management Solution
6
# Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
8
# This program is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU Affero General Public License as
10
# published by the Free Software Foundation, either version 3 of the
11
# License, or (at your option) any later version.
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU Affero General Public License for more details.
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
##############################################################################
22
from osv import fields, osv
24
from datetime import datetime
25
from dateutil.relativedelta import relativedelta
26
from tools.translate import _
28
class account_model_line(osv.osv):
29
_name = "account.model.line"
30
_inherit = "account.model.line"
32
def _get_distribution_state(self, cr, uid, ids, name, args, context=None):
34
Get state of distribution:
35
- if compatible with the invoice line, then "valid"
36
- if no distribution, take a tour of invoice distribution, if compatible, then "valid"
37
- if no distribution on invoice line and invoice, then "none"
38
- all other case are "invalid"
43
if isinstance(ids, (int, long)):
47
# Browse all given lines
48
for line in self.browse(cr, uid, ids, context=context):
49
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)
52
def _have_analytic_distribution_from_header(self, cr, uid, ids, name, arg, context=None):
54
If model has an analytic distribution, return False, else return True
59
if isinstance(ids, (int, long)):
62
for model in self.browse(cr, uid, ids, context=context):
64
if model.analytic_distribution_id:
68
def _get_is_allocatable(self, cr, uid, ids, name, arg, context=None):
70
If expense account, then this account is allocatable.
72
if isinstance(ids, (int, long)):
75
for model_line in self.browse(cr, uid, ids):
76
res[model_line.id] = True
77
if model_line.account_id and model_line.account_id.user_type and model_line.account_id.user_type.code and model_line.account_id.user_type.code != 'expense':
78
res[model_line.id] = False
81
def _get_distribution_state_recap(self, cr, uid, ids, name, arg, context=None):
83
Get a recap from analytic distribution state and if it come from header or not.
85
if isinstance(ids, (int, long)):
88
for model_line in self.browse(cr, uid, ids):
89
res[model_line.id] = ''
90
if not model_line.is_allocatable:
93
if model_line.have_analytic_distribution_from_header:
94
from_header = _(' (from header)')
95
ana_distri_state = self.pool.get('ir.model.fields').get_browse_selection(cr, uid, model_line, 'analytic_distribution_state', context)
96
res[model_line.id] = "%s%s" % (ana_distri_state, from_header)
100
'analytic_distribution_state': fields.function(_get_distribution_state, method=True, type='selection',
101
selection=[('none', 'None'), ('valid', 'Valid'), ('invalid', 'Invalid')],
102
string="Distribution state", help="Informs from distribution state among 'none', 'valid', 'invalid."),
103
'have_analytic_distribution_from_header': fields.function(_have_analytic_distribution_from_header, method=True, type='boolean',
104
string='Header Distrib.?'),
105
'is_allocatable': fields.function(_get_is_allocatable, method=True, type='boolean', string="Is allocatable?", readonly=True, store=False),
106
'analytic_distribution_state_recap': fields.function(_get_distribution_state_recap, method=True, type='char', size=30,
107
string="Distribution",
108
help="Informs you about analaytic distribution state among 'none', 'valid', 'invalid', from header or not, or no analytic distribution"),
109
'sequence': fields.integer('Sequence', readonly=True, help="The sequence field is used to order the resources from lower sequences to higher ones"),
110
'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
114
'have_analytic_distribution_from_header': lambda *a: True,
115
'is_allocatable': lambda *a: True,
116
'analytic_distribution_state_recap': lambda *a: '',
120
def create(self, cr, uid, vals, context=None):
121
model = self.pool.get('account.model').browse(cr, uid, vals['model_id'], context=context)
122
# just add the next line
123
vals['sequence'] = len(model.lines_id) + 1
124
return super(account_model_line, self).create(cr, uid, vals, context=context)
127
def button_analytic_distribution(self, cr, uid, ids, context=None):
129
Launch analytic distribution wizard on an invoice line
134
if isinstance(ids, (int, long)):
137
raise osv.except_osv(_('Error'), _('No model line given. Please save your model line before.'))
138
model_line = self.browse(cr, uid, ids[0], context=context)
140
amount = abs(model_line.debit - model_line.credit)
141
company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
142
currency = model_line.model_id and model_line.model_id.currency_id and model_line.model_id.currency_id.id or company_currency
143
# Get analytic distribution id from this line
144
distrib_id = model_line.analytic_distribution_id and model_line.analytic_distribution_id.id or False
145
# Prepare values for wizard
147
'total_amount': amount,
148
'model_line_id': model_line.id,
149
'currency_id': currency or False,
151
'account_id': model_line.account_id.id,
154
vals.update({'distribution_id': distrib_id,})
156
wiz_obj = self.pool.get('analytic.distribution.wizard')
157
wiz_id = wiz_obj.create(cr, uid, vals, context=context)
158
# Update some context values
165
'name': _('Analytic distribution'),
166
'type': 'ir.actions.act_window',
167
'res_model': 'analytic.distribution.wizard',
175
def copy_data(self, cr, uid, id, default=None, context=None):
177
Copy global distribution and give it to new model line
184
# Copy analytic distribution
185
model_line = self.browse(cr, uid, [id], context=context)[0]
186
if model_line.analytic_distribution_id:
187
new_distrib_id = self.pool.get('analytic.distribution').copy(cr, uid, model_line.analytic_distribution_id.id, {}, context=context)
189
default.update({'analytic_distribution_id': new_distrib_id})
190
return super(account_model_line, self).copy_data(cr, uid, id, default, context)
194
class account_model(osv.osv):
195
_name = "account.model"
196
_inherit = "account.model"
199
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
200
'analytic_distribution_id': fields.many2one('analytic.distribution', 'Analytic Distribution'),
204
'currency_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
207
# @@@override@account.account_model.generate()
208
def generate(self, cr, uid, ids, datas={}, context=None):
211
account_move_obj = self.pool.get('account.move')
212
account_move_line_obj = self.pool.get('account.move.line')
213
pt_obj = self.pool.get('account.payment.term')
214
ana_obj = self.pool.get('analytic.distribution')
219
if datas.get('date', False):
220
context.update({'date': datas['date']})
222
period_id = self.pool.get('account.period').find(cr, uid, dt=context.get('date', False))
224
raise osv.except_osv(_('No period found !'), _('Unable to find a valid period !'))
225
period_id = period_id[0]
227
for model in self.browse(cr, uid, ids, context=context):
228
entry['name'] = model.name%{'year':time.strftime('%Y'), 'month':time.strftime('%m'), 'date':time.strftime('%Y-%m')}
229
move_id = account_move_obj.create(cr, uid, {
230
'ref': entry['name'],
231
'period_id': period_id,
232
'journal_id': model.journal_id.id,
233
'date': context.get('date',time.strftime('%Y-%m-%d'))
235
move_ids.append(move_id)
236
for line in model.lines_id:
239
'journal_id': model.journal_id.id,
240
'period_id': period_id,
242
if line.account_id.user_type_code == 'expense':
243
if line.analytic_distribution_state == 'invalid':
244
raise osv.except_osv(_('Invalid Analytic Distribution !'),_("You have to define a valid analytic distribution on the '%s' line or header!") % (line.name))
245
if not model.journal_id.analytic_journal_id:
246
raise osv.except_osv(_('No Analytic Journal !'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
247
if line.analytic_distribution_id:
248
new_distribution_id = ana_obj.copy(cr, uid, line.analytic_distribution_id.id, {}, context=context)
249
val.update({'analytic_distribution_id': new_distribution_id})
250
elif model.analytic_distribution_id:
251
new_distribution_id = ana_obj.copy(cr, uid, model.analytic_distribution_id.id, {}, context=context)
252
val.update({'analytic_distribution_id': new_distribution_id})
254
date_maturity = time.strftime('%Y-%m-%d')
255
if line.date_maturity == 'partner':
256
if not line.partner_id:
257
raise osv.except_osv(_('Error !'), _("Maturity date of entry line generated by model line '%s' of model '%s' is based on partner payment term!" \
258
"\nPlease define partner on it!")%(line.name, model.name))
259
if line.partner_id.property_payment_term:
260
payment_term_id = line.partner_id.property_payment_term.id
261
pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_maturity)
263
pterm_list = [l[0] for l in pterm_list]
265
date_maturity = pterm_list[-1]
269
'quantity': line.quantity,
270
'debit_currency': line.debit, # UF-1535: set this value as the booking currency, and not functional currency
271
'credit_currency': line.credit, # UF-1535: set this value as the booking currency, and not functional currency
272
'account_id': line.account_id.id,
274
'partner_id': line.partner_id.id,
275
'date': context.get('date',time.strftime('%Y-%m-%d')),
276
'document_date': context.get('date',time.strftime('%Y-%m-%d')),
277
'date_maturity': date_maturity,
278
'currency_id': model.currency_id.id,
279
'is_recurring': True,
282
c.update({'journal_id': model.journal_id.id,'period_id': period_id})
283
account_move_line_obj.create(cr, uid, val, context=c)
287
def button_analytic_distribution(self, cr, uid, ids, context=None):
289
Launch analytic distribution wizard on a model
294
if isinstance(ids, (int, long)):
296
# Prepare some values
297
model = self.browse(cr, uid, ids[0], context=context)
299
# Search elements for currency
300
company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
301
currency = model.currency_id and model.currency_id.id or company_currency
302
for line in model.lines_id:
303
amount += (line.debit - line.credit)
305
# Get analytic_distribution_id
306
distrib_id = model.analytic_distribution_id and model.analytic_distribution_id.id
307
# Prepare values for wizard
309
'total_amount': amount,
310
'model_id': model.id,
311
'currency_id': currency or False,
315
vals.update({'distribution_id': distrib_id,})
317
wiz_obj = self.pool.get('analytic.distribution.wizard')
318
wiz_id = wiz_obj.create(cr, uid, vals, context=context)
319
# Update some context values
326
'name': _('Global analytic distribution'),
327
'type': 'ir.actions.act_window',
328
'res_model': 'analytic.distribution.wizard',
338
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: