~vauxoo/addons-vauxoo/6.0-trunk

« back to all changes in this revision

Viewing changes to ifrs_report/model/ifrs.py

  • Committer: nhomar at vauxoo
  • Date: 2011-06-11 22:55:27 UTC
  • Revision ID: nhomar@vauxoo.com-20110611225527-v2mlv4fbx38j0gg3
[SHELDON ] commiting ortografy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- encoding: utf-8 -*-
2
 
#!/usr/bin/python
3
 
###########################################################################
4
 
#    Module Writen to OpenERP, Open Source Management Solution
5
 
#    Copyright (C) OpenERP Venezuela (<http://openerp.com.ve>).
6
 
#    All Rights Reserved
7
 
# Credits######################################################
8
 
#    Coded by: Katherine Zaoral <katherine.zaoral@vauxoo.com>
9
 
#    Coded by: Yanina Aular <yanina.aular@vauxoo.com>
10
 
#    Planified by: Humberto Arocha <hbto@vauxoo.com>
11
 
#    Audited by: Nhomar Hernandez <nhomar@vauxoo.com>
12
 
#############################################################################
13
 
#    This program is free software: you can redistribute it and/or modify
14
 
#    it under the terms of the GNU Affero General Public License as published by
15
 
#    the Free Software Foundation, either version 3 of the License, or
16
 
#    (at your option) any later version.
17
 
#
18
 
#    This program is distributed in the hope that it will be useful,
19
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 
#    GNU Affero General Public License for more details.
22
 
#
23
 
#    You should have received a copy of the GNU Affero General Public License
24
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 
##########################################################################
26
 
 
27
 
from osv import osv
28
 
from osv import fields
29
 
from tools.translate import _
30
 
import time
31
 
#~ import pdb
32
 
 
33
 
class ifrs_ifrs(osv.osv):
34
 
 
35
 
    _name = 'ifrs.ifrs'
36
 
    _rec_name = 'code'
37
 
 
38
 
    def onchange_company_id(self, cr, uid, ids, company_id, context=None):
39
 
        context = context or {}
40
 
        context['company_id'] = company_id
41
 
        res = {'value': {}}
42
 
 
43
 
        if not company_id:
44
 
            return res
45
 
 
46
 
        cur_id = self.pool.get('res.company').browse(
47
 
            cr, uid, company_id, context=context).currency_id.id
48
 
        fy_id = self.pool.get('account.fiscalyear').find(
49
 
            cr, uid, context=context)
50
 
 
51
 
        res['value'].update({'fiscalyear_id': fy_id})
52
 
        res['value'].update({'currency_id': cur_id})
53
 
        return res
54
 
 
55
 
    _columns = {
56
 
        'name': fields.char('Name', 128, required=True, help='Report name'),
57
 
        'company_id': fields.many2one('res.company', string='Company', ondelete='cascade', help='Company name'),
58
 
        'currency_id': fields.related('company_id', 'currency_id', type='many2one', relation='res.currency', string='Company Currency', help="Currency at which this report will be expressed. If not selected will be used the one set in the company"),
59
 
        'title': fields.char('Title', 128, required=True, translate=True, help='Report title that will be printed'),
60
 
        'code': fields.char('Code', 128, required=True, help='Report code'),
61
 
        'description': fields.text('Description'),
62
 
        'ifrs_lines_ids': fields.one2many('ifrs.lines', 'ifrs_id', 'IFRS lines'),
63
 
        'state': fields.selection([
64
 
            ('draft', 'Draft'),
65
 
            ('ready', 'Ready'),
66
 
            ('done', 'Done'),
67
 
            ('cancel', 'Cancel')],
68
 
            'State', required=True),
69
 
        'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', help='Fiscal Year'),
70
 
        'help': fields.boolean('Show Help', help='Allows you to show the help in the form'),
71
 
        'ifrs_ids': fields.many2many('ifrs.ifrs', 'ifrs_m2m_rel', 'parent_id', 'child_id', string='Other Reportes',)
72
 
    }
73
 
 
74
 
    _defaults = {
75
 
        'state': 'draft',
76
 
        'help': True,
77
 
        'company_id': lambda s, c, u, cx: s.pool.get('res.users').browse(
78
 
            c, u, u, context=cx).company_id.id,
79
 
        'fiscalyear_id': lambda s, c, u, cx: \
80
 
                s.pool.get('account.fiscalyear').find(c, u,exception=False),
81
 
    }
82
 
 
83
 
    def _get_level(self, cr, uid, l, level, tree, context=None):
84
 
        """ Calcula los niveles de los ifrs.lines, tomando en cuenta que sera
85
 
        un mismo arbol para los campos total_ids y operand_ids.
86
 
        @param l: objeto a un ifrs.lines
87
 
        @param level: Nivel actual de la recursion
88
 
        @param tree: Arbol de dependencias entre lineas construyendose
89
 
        """
90
 
        context = context or {}
91
 
        if not tree.get(level):
92
 
            tree[level] = {}
93
 
        # The search through level should be backwards from the deepest level to
94
 
        # the outmost level
95
 
        levels = tree.keys()
96
 
        levels.sort()
97
 
        levels.reverse()
98
 
        xlevel = False
99
 
        for n in levels:
100
 
            xlevel = isinstance(tree[n].get(l.id), (set)) and n or xlevel
101
 
        if not xlevel:
102
 
            tree[level][l.id] = set()
103
 
        elif xlevel < level:
104
 
            tree[level][l.id] = tree[xlevel][l.id]
105
 
            del tree[xlevel][l.id]
106
 
        else:  # xlevel >= level
107
 
            return True
108
 
        for j in set(l.total_ids + l.operand_ids):
109
 
            tree[level][l.id].add(j.id)
110
 
            self._get_level(cr, uid, j, level+1, tree, context=context)
111
 
        return True
112
 
 
113
 
    def _get_ordered_lines(self, cr, uid, ids, context=None):
114
 
        """ Return list of browse ifrs_lines per level in order ASC, for can
115
 
        calculate in order of depending.
116
 
 
117
 
        Retorna la lista de ifrs.lines del ifrs_id organizados desde el nivel
118
 
        mas bajo hasta el mas alto. Lo niveles mas bajos se deben calcular
119
 
        primero, por eso se posicionan en primer lugar de la lista.
120
 
        """
121
 
        context = context or {}
122
 
        ids = isinstance(ids, (int, long)) and [ids] or ids
123
 
        ifrs_brw = self.browse(cr, uid, ids[0], context=context)
124
 
        tree = {1: {}}
125
 
        level = 1
126
 
        for l in ifrs_brw.ifrs_lines_ids:
127
 
            self._get_level(cr, uid, l, level, tree, context=context)
128
 
        levels = tree.keys()
129
 
        levels.sort()
130
 
        levels.reverse()
131
 
        ids_o = [i.id for i in ifrs_brw.ifrs_lines_ids]
132
 
        ids_x = []  # List of ids per level in order ASC
133
 
        for i in levels:
134
 
            ids_x += tree[i].keys()
135
 
        ifrs_lines = self.pool.get('ifrs.lines')
136
 
        res = []
137
 
        res = ifrs_lines.browse(
138
 
            cr, uid, ids_x, context=context)  # List of browse per level in order ASC
139
 
        return res
140
 
 
141
 
    def compute(self, cr, uid, ids, context=None):
142
 
        """ Se encarga de calcular los montos para visualizarlos desde
143
 
        el formulario del ifrs, hace una llamada al get_report_data, el
144
 
        cual se encarga de realizar los calculos.
145
 
        """
146
 
        context = context or {}
147
 
        ids = isinstance(ids, (int, long)) and [ids] or ids
148
 
        fy = self.browse(cr, uid, ids, context=context)[0]
149
 
        context.update({'whole_fy': True, 'fiscalyear': fy.fiscalyear_id.id})
150
 
        ifrs_lines = self.pool.get('ifrs.lines')
151
 
        self.get_report_data(cr, uid, ids, is_compute=True, context=context)
152
 
        return True
153
 
 
154
 
    def _get_periods_name_list(self, cr, uid, ids, fiscalyear_id, context=None):
155
 
        """ Devuelve una lista con la info de los periodos fiscales
156
 
        (numero mes, id periodo, nombre periodo)
157
 
        @param fiscalyear_id: Año fiscal escogido desde el wizard encargada
158
 
        de preparar el reporte para imprimir
159
 
        """
160
 
        if context is None:
161
 
            context = {}
162
 
 
163
 
        period_list = []
164
 
        period_list.append(('0', None, ' '))
165
 
 
166
 
        fiscalyear_bwr = self.pool.get('account.fiscalyear').browse(
167
 
            cr, uid, fiscalyear_id, context=context)
168
 
 
169
 
        periods_ids = fiscalyear_bwr._get_fy_period_ids()
170
 
 
171
 
        periods = self.pool.get('account.period')
172
 
 
173
 
        for ii, period_id in enumerate(periods_ids, start=1):
174
 
            period_list.append((str(ii), period_id, periods.browse(
175
 
                cr, uid, period_id, context=context).name))
176
 
        return period_list
177
 
        
178
 
 
179
 
    def _get_period_print_info(self, cr, uid, ids, period_id, report_type, context=None):
180
 
        """ Return all the printable information about period
181
 
        @param period_id: Dependiendo del report_type, en el caso que sea 'per',
182
 
        este campo indica el periodo a tomar en cuenta, en caso de que el
183
 
        report_type sea 'all', es Falso.
184
 
        @param report_type: Su valor se establece desde el wizard que se encarga
185
 
        de preparar al reporte para imprimir, el report_type puede ser 'all' (incluir
186
 
        todo el año fiscal en el reporte) o 'per' (tomar en cuenta solo un periodo
187
 
        determinado en el reporte)
188
 
        """
189
 
        if context is None:
190
 
            context = {}
191
 
        if report_type == 'all':
192
 
            res = _('ALL PERIODS OF THE FISCALYEAR')
193
 
        else:
194
 
            period = self.pool.get('account.period').browse(
195
 
                cr, uid, period_id, context=context)
196
 
            res = str(period.name) + ' [' + str(period.code) + ']'
197
 
        return res
198
 
 
199
 
    def step_sibling(self, cr, uid, old_id, new_id, context=None):
200
 
        '''
201
 
        Sometimes total_ids and operand_ids include lines from their own
202
 
        ifrs_id report, They are siblings. In this case m2m copy_data just make
203
 
        a link from the old report.
204
 
        In the new report we have to substitute the cousins that are pretending
205
 
        to be siblings with the siblings
206
 
        This can be achieved due to the fact that each line has unique sequence
207
 
        within each report, using the analogy about relatives then each
208
 
        pretending cousin is of same age than that of the actual sibling
209
 
        cousins with common parent are siblings among them
210
 
        '''
211
 
        context = context or {}
212
 
 
213
 
        old_brw = self.browse(cr, uid, old_id, context=context)
214
 
        new_brw = self.browse(cr, uid, new_id, context=context)
215
 
        il_obj = self.pool.get('ifrs.lines')
216
 
 
217
 
        sibling_ids = {} 
218
 
        markt=[]
219
 
        marko=[]
220
 
        for l in old_brw.ifrs_lines_ids:
221
 
            for t in l.total_ids:
222
 
                if t.ifrs_id.id == l.ifrs_id.id:
223
 
                    sibling_ids[t.sequence]= t.id
224
 
                    markt.append(l.sequence)
225
 
            for o in l.operand_ids:
226
 
                if o.ifrs_id.id == l.ifrs_id.id:
227
 
                    sibling_ids[o.sequence]= o.id
228
 
                    marko.append(l.sequence)
229
 
 
230
 
        if not sibling_ids: return True
231
 
        
232
 
        markt = markt and set(markt) or []
233
 
        marko = marko and set(marko) or []
234
 
 
235
 
        o2n={}
236
 
        for seq in  sibling_ids:
237
 
            ns_id = il_obj.search(cr,uid,[ ('sequence','=',seq),
238
 
                ('ifrs_id','=',new_id) ],context=context)
239
 
            o2n[sibling_ids[seq]] = ns_id[0]
240
 
 
241
 
        for nl in new_brw.ifrs_lines_ids:
242
 
            if nl.sequence in markt:
243
 
                tt = [o2n.get(nt.id,nt.id) for nt in nl.total_ids]
244
 
                nl.write({'total_ids':[(6,0,tt)]})
245
 
            if nl.sequence in marko:
246
 
                oo = [o2n.get(no.id,no.id) for no in nl.operand_ids]
247
 
                nl.write({'operand_ids':[(6,0,oo)]})
248
 
 
249
 
        return True
250
 
 
251
 
    def copy_data(self, cr, uid, id, default=None, context=None):
252
 
        res = super(ifrs_ifrs, self).copy_data(cr, uid, id, default, context)
253
 
        if res['ifrs_lines_ids'] and context.get('clear_cons_ids', False):
254
 
            for l in res['ifrs_lines_ids']:
255
 
                l[2]['cons_ids'] = l[2]['type']=='detail' and l[2]['cons_ids']\
256
 
                        and [] or []
257
 
        return res
258
 
 
259
 
    def copy(self, cr, uid, id, default=None, context=None):
260
 
        context = context or {}
261
 
        default = default or {}
262
 
        ru_brw = self.pool.get('res.users').browse(cr, uid, uid, context=context)
263
 
        ii_brw = self.pool.get('ifrs.ifrs').browse(cr, uid, id, context=context)
264
 
        if ru_brw.company_id.id != ii_brw.company_id.id:
265
 
            context['clear_cons_ids']=True
266
 
            default['company_id'] = ru_brw.company_id.id
267
 
            default['fiscalyear_id'] = self.pool.get('account.fiscalyear').find(
268
 
                    cr, uid, exception=False, context=context)
269
 
        res = super(ifrs_ifrs, self).copy(cr, uid, id, default, context)
270
 
        self.step_sibling(cr, uid, id, res, context=context)
271
 
        return res
272
 
   
273
 
    def _get_children_and_consol(self, cr, uid, ids, level, context={}):
274
 
       """ Retorna todas las cuentas relacionadas con las cuentas ids 
275
 
       recursivamente, incluyendolos
276
 
       """
277
 
       aa_obj = self.pool.get('account.account')                           
278
 
       ids2 = []                                                           
279
 
       for aa_brw in aa_obj.browse(cr, uid, ids, context):                 
280
 
           if not aa_brw.child_id and aa_brw.level < level and aa_brw.type not in ('consolidation','view'):
281
 
               ids2.append(aa_brw.id)
282
 
           else:                                                           
283
 
               ids2.append(aa_brw.id)
284
 
               ids2 += self._get_children_and_consol(cr, uid, [x.id for x in aa_brw.child_id], level, context=context)
285
 
       return list(set(ids2)) 
286
 
    
287
 
    def get_num_month(self, cr, uid, id, fiscalyear, period, context=None):
288
 
        accountfy_obj = self.pool.get('account.fiscalyear')
289
 
        return accountfy_obj._get_fy_month(cr, uid, fiscalyear, period, special=False, context=context)
290
 
 
291
 
 
292
 
    def get_report_data(
293
 
        self, cr, uid, ids, fiscalyear=None, exchange_date=None,
294
 
            currency_wizard=None, target_move=None, period=None, two=None, is_compute=None, context=None):
295
 
        """ Metodo que se encarga de retornar un diccionario con los montos
296
 
        totales por periodo de cada linea, o la sumatoria de todos montos
297
 
        por periodo de cada linea. La información del diccionario se utilizara
298
 
        para llenar el reporte, ya sea de dos columnas o de 12 columnas.
299
 
        @param fiscalyear: Año fiscal que se reflejara en el reporte
300
 
        @param exchange_date:
301
 
        @param currency_wizard: Moneda que se reflejara en el reporte
302
 
        @param target_move: Asientos contables a tomar en cuenta en los calculos
303
 
        @param period: Periodo a reflejar en caso de que no se tome en cuenta todo el año fiscal
304
 
        @param two: Nos dice si el reporte es de 2 o 12 columnas
305
 
        """
306
 
        if context is None:
307
 
            context = {}
308
 
 
309
 
        data = []
310
 
 
311
 
        ifrs_line = self.pool.get('ifrs.lines')
312
 
        
313
 
        if is_compute is None:
314
 
            period_name = self._get_periods_name_list(
315
 
                cr, uid, ids, fiscalyear, context=context)
316
 
 
317
 
        ordered_lines = self._get_ordered_lines(cr, uid, ids, context=context)
318
 
 
319
 
        if is_compute:  # Si es llamado desde el metodo compute, solo se actualizaran los montos y no se creara el diccionario
320
 
            for ifrs_l in ordered_lines:
321
 
                ifrs_line._get_amount_with_operands(cr, uid,
322
 
                ids, ifrs_l, is_compute=True, context=context)
323
 
        else:
324
 
            if two:
325
 
                for ifrs_l in ordered_lines:
326
 
                    amount_value = ifrs_line._get_amount_with_operands(cr, uid,
327
 
                       ids, ifrs_l, period_name, fiscalyear, exchange_date,
328
 
                       currency_wizard, period, target_move, two=two,
329
 
                       context=context)
330
 
                    
331
 
                    line = {'sequence': int(ifrs_l.sequence), 'id': ifrs_l.id, 'name': ifrs_l.name, 'invisible': ifrs_l.invisible, 'type': str(
332
 
                        ifrs_l.type), 'amount': amount_value,'comparison':ifrs_l.comparison,'operator':ifrs_l.operator}
333
 
                    
334
 
                    if ifrs_l.ifrs_id.id == ids[0]:  # Se toman las lineas del ifrs actual, ya que en los calculos se incluyen lineas de otros ifrs
335
 
                        data.append(line)
336
 
                    data.sort(key=lambda x: int(x['sequence']))
337
 
 
338
 
            else:
339
 
                for ifrs_l in ordered_lines:
340
 
                    line = {
341
 
                    'sequence': int(ifrs_l.sequence), 'id': ifrs_l.id, 'name': ifrs_l.name,
342
 
                    'invisible': ifrs_l.invisible, 'type': ifrs_l.type,
343
 
                    'period': {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0},
344
 
                    'comparison':ifrs_l.comparison,'operator':ifrs_l.operator}
345
 
                    for lins in range(1, 13):
346
 
                        amount_value = ifrs_line._get_amount_with_operands(
347
 
                                cr, uid,
348
 
                                ids, ifrs_l, period_name, fiscalyear, exchange_date,
349
 
                                currency_wizard, lins, target_move,
350
 
                                context=context)
351
 
                        line['period'][lins] = amount_value
352
 
 
353
 
                    if ifrs_l.ifrs_id.id == ids[0]:  
354
 
                        # Se toman las lineas del ifrs actual, ya que en los
355
 
                        # calculos se incluyen lineas de otros ifrs
356
 
                        data.append(line)
357
 
                    data.sort(key=lambda x: int(x['sequence']))
358
 
                    
359
 
        for i in xrange(1, 13):
360
 
            cr.execute("update ifrs_lines set period_" + str(i) +"= 0.0;" )
361
 
        return data
362
 
 
363
 
 
364
 
class ifrs_lines(osv.osv):
365
 
 
366
 
    _name = 'ifrs.lines'
367
 
    _parent_store = True
368
 
    _order = 'ifrs_id, sequence'
369
 
   
370
 
    def _get_sum_operator(self, cr, uid, brw, number_month=None, is_compute=None, context=None):
371
 
        """ Calculates the sum of the line operand_ids the current ifrs.line
372
 
        @param number_month: periodo a calcular
373
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
374
 
        """
375
 
        if context is None:
376
 
            context = {}
377
 
        res = 0
378
 
 
379
 
        # If the report is two or twelve columns, will choose the field needed
380
 
        # to make the sum
381
 
        if is_compute:
382
 
            field_name = 'amount'
383
 
        else:
384
 
            if context.get('whole_fy', False):
385
 
                field_name = 'ytd'
386
 
            else:
387
 
                field_name = 'period_%s' % str(number_month)
388
 
 
389
 
        # It takes the sum of the operands 
390
 
        for t in brw.operand_ids:
391
 
            res += getattr(t, field_name)
392
 
        return res
393
 
 
394
 
    def _get_sum_total(self, cr, uid, brw, number_month=None, is_compute=None, context=None):
395
 
        """ Calculates the sum of the line total_ids the current ifrs.line
396
 
        @param number_month: periodo a calcular
397
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
398
 
        """
399
 
        if context is None:
400
 
            context = {}
401
 
        res = 0
402
 
 
403
 
        # If the report is two or twelve columns, will choose the field needed
404
 
        # to make the sum
405
 
        if is_compute:
406
 
            field_name = 'amount'
407
 
        else:
408
 
            if context.get('whole_fy', False):
409
 
                field_name = 'ytd'
410
 
            else:
411
 
                field_name = 'period_%s' % str(number_month)
412
 
 
413
 
        # It takes the sum of the total_ids
414
 
        for t in brw.total_ids:
415
 
            res += getattr(t, field_name)
416
 
        return res
417
 
 
418
 
    def _get_sum_detail(self, cr, uid, id=None, number_month=None, is_compute=None, context=None):
419
 
        """ Calculates the amount sum of the line type == 'detail'
420
 
        @param number_month: periodo a calcular
421
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
422
 
        """
423
 
        fy_obj = self.pool.get('account.fiscalyear')
424
 
        period_obj = self.pool.get('account.period')
425
 
        context = context or {}
426
 
        cx = context.copy()
427
 
        res = 0.0
428
 
 
429
 
        if not cx.get('fiscalyear'):
430
 
            cx['fiscalyear'] = fy_obj.find(cr, uid)
431
 
 
432
 
        fy_id = cx['fiscalyear']
433
 
 
434
 
        brw = self.browse(cr, uid, id)
435
 
 
436
 
        if brw.acc_val == 'init':
437
 
            if cx.get('whole_fy',False):
438
 
                cx['periods'] = period_obj.search(cr, uid, [
439
 
                    ('fiscalyear_id','=',fy_id),('special','=',True)])
440
 
            else:
441
 
                period_from = period_obj.search(cr, uid, [
442
 
                    ('fiscalyear_id','=',fy_id),('special','=',True)])
443
 
                # Case when the period_from is the first non-special period
444
 
                # of the fiscalyear
445
 
                if period_obj.browse(cr, uid, cx['period_from']).date_start ==\
446
 
                    fy_obj.browse(cr, uid, fy_id).date_start:
447
 
                    cx['period_to'] = period_from[0]
448
 
                else:
449
 
                    cx['period_to'] = period_obj.previous(
450
 
                            cr, uid, cx['period_from'])
451
 
                cx['period_from'] = period_from[0]
452
 
        elif brw.acc_val == 'var':
453
 
            #it is going to be the one sent by the previous cx
454
 
            if cx.get('whole_fy',False):
455
 
                cx['periods'] = period_obj.search(cr, uid, [
456
 
                    ('fiscalyear_id','=',fy_id),('special','=',False)])
457
 
        else:
458
 
            #it is going to be from the fiscalyear's beginning
459
 
            if cx.get('whole_fy',False):
460
 
                cx['periods'] = period_obj.search(cr, uid, [
461
 
                    ('fiscalyear_id','=',fy_id)])
462
 
            else:
463
 
                period_from = period_obj.search(cr, uid, [
464
 
                    ('fiscalyear_id','=',fy_id),('special','=',True)])
465
 
                cx['period_from'] = period_from[0]
466
 
                cx['periods'] = period_obj.build_ctx_periods(cr, uid,
467
 
                    cx['period_from'], cx['period_to'])
468
 
 
469
 
        brw = self.browse(cr, uid, id, context=cx)
470
 
 
471
 
        if brw.type == 'detail':
472
 
            # Si es de tipo detail
473
 
            analytic = [an.id for an in brw.analytic_ids]
474
 
                # Tomo los ids de las cuentas analiticas de las lineas
475
 
            if analytic:  
476
 
                # Si habian cuentas analiticas en la linea, se guardan en el
477
 
                # context y se usan en algun metodo dentro del modulo de
478
 
                # account
479
 
                cx['analytic'] = analytic
480
 
            cx['partner_detail'] = cx.get('partner_detail')
481
 
            
482
 
            for aa in brw.cons_ids:  
483
 
                # Se hace la sumatoria de la columna balance, credito o debito.
484
 
                # Dependiendo de lo que se escoja en el wizard
485
 
                if brw.value == 'debit':
486
 
                    res += aa.debit
487
 
                elif brw.value == 'credit':
488
 
                    res += aa.credit
489
 
                else:
490
 
                    res += aa.balance
491
 
        return res
492
 
 
493
 
    def _get_grand_total(self, cr, uid, id=None, number_month=None, is_compute=None, context=None):
494
 
        """ Calculates the amount sum of the line type == 'total'
495
 
        @param number_month: periodo a calcular
496
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
497
 
        """
498
 
        fy_obj = self.pool.get('account.fiscalyear')
499
 
        context = context or {}
500
 
        cx = context.copy()
501
 
        res = 0.0
502
 
 
503
 
        if not cx.get('fiscalyear'):
504
 
            cx['fiscalyear'] = fy_obj.find(cr, uid)
505
 
 
506
 
        fy_id = cx['fiscalyear']
507
 
 
508
 
        brw = self.browse(cr, uid, id)
509
 
        res = self._get_sum_total( cr, uid, brw, number_month, is_compute,
510
 
                context=cx)
511
 
 
512
 
        if brw.operator in ('subtract','percent','ratio','product'):
513
 
            so = self._get_sum_operator( cr, uid, brw, number_month,
514
 
                    is_compute, context=cx)
515
 
            if brw.operator == 'subtract':
516
 
                res -= so
517
 
            elif brw.operator == 'percent':
518
 
                res = so != 0 and (100 * res / so) or 0.0
519
 
            elif brw.operator == 'ratio':
520
 
                res = so != 0 and (res / so) or 0.0
521
 
            elif brw.operator == 'product':
522
 
                res = res * so
523
 
        return res
524
 
 
525
 
    def _get_constant(self, cr, uid, id=None, number_month=None, is_compute=None, context=None):
526
 
        """ Calculates the amount sum of the line of constant
527
 
        @param number_month: periodo a calcular
528
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
529
 
        """
530
 
        cx = context or {}
531
 
        brw = self.browse(cr, uid, id, context=cx)
532
 
        fy_obj = self.pool.get('account.fiscalyear')
533
 
        period_obj = self.pool.get('account.period')
534
 
 
535
 
        if not cx.get('fiscalyear'):
536
 
            cx['fiscalyear'] = fy_obj.find(cr, uid, dt=None, context=cx)
537
 
 
538
 
        if not cx.get('period_from', False) and not cx.get('period_to', False):
539
 
            if context.get('whole_fy', False):
540
 
                cx['period_from'] = period_obj.search(cr, uid, [(
541
 
                    'fiscalyear_id', '=', cx['fiscalyear']), ('special', '=', True)])
542
 
                if not cx['period_from']:
543
 
                    raise osv.except_osv(_('Error !'), _('There are no special period in %s') % (
544
 
                        fy_obj.browse(cr, uid, cx['fiscalyear'], context=cx).name))
545
 
                cx['period_from'] = cx['period_from'][0]
546
 
            cx['period_to'] = period_obj.search(cr, uid, [
547
 
                                               ('fiscalyear_id', '=', cx['fiscalyear'])])[-1]
548
 
 
549
 
        if brw.constant_type == 'period_days':
550
 
            res = period_obj._get_period_days(
551
 
                cr, uid, cx['period_from'], cx['period_to'])
552
 
        elif brw.constant_type == 'fy_periods':
553
 
            res = fy_obj._get_fy_periods(cr, uid, cx['fiscalyear'])
554
 
        elif brw.constant_type == 'fy_month':
555
 
            res = fy_obj._get_fy_month(cr, uid, cx[
556
 
                                       'fiscalyear'], cx['period_to'])
557
 
        elif brw.constant_type == 'number_customer':
558
 
            res = self._get_number_customer_portfolio(cr, uid, id, cx[
559
 
                                       'fiscalyear'], cx['period_to'], cx)
560
 
        return res
561
 
 
562
 
    def _get_level(self, cr, uid, ids, field_name, arg, context=None):
563
 
        res = {}
564
 
        for ifrs_line in self.browse(cr, uid, ids, context=context):
565
 
            level = 0
566
 
            parent = ifrs_line.parent_id
567
 
            while parent:
568
 
                level += 1
569
 
                parent = parent.parent_id
570
 
            res[ifrs_line.id] = level
571
 
        return res
572
 
 
573
 
    def _get_children_and_total(self, cr, uid, ids, context=None):
574
 
        """this function search for all the children and all consolidated children (recursively) of the given total ids
575
 
        """
576
 
        ids3 = []
577
 
        ids2 = []
578
 
        sql = 'select * from ifrs_lines_rel where parent_id in (' + ','.join(
579
 
            map(str, ids)) + ')'
580
 
        cr.execute(sql)
581
 
        childs = cr.fetchall()
582
 
        for rec in childs:
583
 
            ids2.append(rec[1])
584
 
            self.write(cr, uid, rec[1], {'parent_id': rec[0]})
585
 
            rec = self.browse(cr, uid, rec[1], context=context)
586
 
            for child in rec.total_ids:
587
 
                ids3.append(child.id)
588
 
        if ids3:
589
 
            ids3 = self._get_children_and_total(cr, uid, ids3, context=context)
590
 
        return ids2 + ids3
591
 
 
592
 
 
593
 
    def exchange(self, cr, uid, ids, from_amount, to_currency_id, from_currency_id, exchange_date, context=None):
594
 
        if context is None:
595
 
            context = {}
596
 
        if from_currency_id == to_currency_id:
597
 
            return from_amount
598
 
        curr_obj = self.pool.get('res.currency')
599
 
        context['date'] = exchange_date
600
 
        return curr_obj.compute(cr, uid, from_currency_id, to_currency_id, from_amount, context=context)
601
 
 
602
 
    def _get_amount_value(self, cr, uid, ids, ifrs_line=None, period_info=None, fiscalyear=None, exchange_date=None, currency_wizard=None, number_month=None, target_move=None, pd=None, undefined=None, two=None, is_compute=None, context=None):
603
 
        if context is None:
604
 
            context = {}
605
 
        """ Returns the amount corresponding to the period of fiscal year
606
 
        @param ifrs_line: linea a calcular monto
607
 
        @param period_info: informacion de los periodos del fiscal year
608
 
        @param fiscalyear: selected fiscal year
609
 
        @param exchange_date: date of change currency
610
 
        @param currency_wizard: currency in the report
611
 
        @param number_month: period number
612
 
        @param target_move: target move to consider
613
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
614
 
        """
615
 
 
616
 
        from_currency_id = ifrs_line.ifrs_id.company_id.currency_id.id
617
 
        to_currency_id = currency_wizard
618
 
 
619
 
        ifrs_line = self.browse(cr, uid, ifrs_line.id)
620
 
 
621
 
        if number_month:
622
 
            if two:
623
 
                context = {
624
 
                    'period_from': number_month, 'period_to': number_month}
625
 
            else:
626
 
                period_id = period_info[number_month][1]
627
 
                context = {'period_from': period_id, 'period_to': period_id}
628
 
        else:
629
 
            context = {'whole_fy': 'True'}
630
 
 
631
 
        context['partner_detail'] = pd
632
 
        context['fiscalyear'] = fiscalyear
633
 
        context['state'] = target_move
634
 
        
635
 
        if ifrs_line.type == 'detail':
636
 
            res = self._get_sum_detail( cr, uid, ifrs_line.id, number_month,
637
 
                    is_compute, context=context)
638
 
        elif ifrs_line.type == 'total':
639
 
            res = self._get_grand_total( cr, uid, ifrs_line.id, number_month,
640
 
                    is_compute, context=context)
641
 
        elif ifrs_line.type == 'constant':
642
 
            res = self._get_constant( cr, uid, ifrs_line.id, number_month,
643
 
                    is_compute, context=context)
644
 
        else:
645
 
            res = 0.0
646
 
 
647
 
        if ifrs_line.type == 'detail':
648
 
            res = self.exchange(
649
 
                cr, uid, ids, res, to_currency_id, from_currency_id, exchange_date, context=context)
650
 
        # Total amounts come from details so if the details are already
651
 
        # converted into the regarding currency then it is not useful to do at
652
 
        # total level
653
 
        #elif ifrs_line.type == 'total':
654
 
        #    if ifrs_line.operator not in ('percent', 'ratio'):
655
 
        #        if ifrs_line.comparison not in ('percent', 'ratio', 'product'):
656
 
        #            res = self.exchange(
657
 
        #                cr, uid, ids, res, to_currency_id, from_currency_id, exchange_date, context=context)
658
 
        return res
659
 
 
660
 
    def _get_amount_with_operands(self, cr, uid, ids, ifrs_line, period_info=None, fiscalyear=None, exchange_date=None, currency_wizard=None, number_month=None, target_move=None, pd=None, undefined=None, two=None, is_compute=None, context=None):
661
 
        if context is None:
662
 
            context = {}
663
 
        """ Integrate operand_ids field in the calculation of the amounts for each line
664
 
        @param ifrs_line: linea a calcular monto
665
 
        @param period_info: informacion de los periodos del fiscal year
666
 
        @param fiscalyear: selected fiscal year
667
 
        @param exchange_date: date of change currency
668
 
        @param currency_wizard: currency in the report
669
 
        @param number_month: period number
670
 
        @param target_move: target move to consider
671
 
        @param is_compute: si el metodo actualizara el campo amount para la vista
672
 
        """
673
 
 
674
 
        ifrs_line = self.browse(cr, uid, ifrs_line.id)
675
 
        if not number_month:
676
 
            context = {'whole_fy': 'True'}
677
 
 
678
 
        if is_compute:
679
 
            field_name = 'amount'
680
 
        else:
681
 
            if context.get('whole_fy', False):
682
 
                field_name = 'ytd'
683
 
            else:
684
 
                field_name = 'period_%s' % str(number_month)
685
 
 
686
 
        res = self._get_amount_value(
687
 
            cr, uid, ids, ifrs_line, period_info, fiscalyear, exchange_date,
688
 
            currency_wizard, number_month, target_move, pd, undefined, two, is_compute, context=context)
689
 
 
690
 
        res = ifrs_line.inv_sign and (-1.0 * res) or res
691
 
        self.write(cr, uid, ifrs_line.id, {field_name: res})
692
 
       
693
 
        return res
694
 
 
695
 
    def _get_partner_detail(self, cr, uid, ids, ifrs_l, context=None):
696
 
        ifrs = self.pool.get('ifrs.lines')
697
 
        aml_obj = self.pool.get('account.move.line')
698
 
        account_obj = self.pool.get('account.account')
699
 
        partner_obj = self.pool.get('res.partner')
700
 
        res = []
701
 
        if ifrs_l.type == 'detail':
702
 
            ids2 = [lin.id for lin in ifrs_l.cons_ids]
703
 
            ids3 = ids2 and account_obj._get_children_and_consol(
704
 
                cr, uid, ids2, context=context) or []
705
 
            if ids3:
706
 
                cr.execute(""" SELECT rp.id
707
 
                    FROM account_move_line l JOIN res_partner rp ON rp.id = l.partner_id
708
 
                    WHERE l.account_id IN %s
709
 
                    GROUP BY rp.id
710
 
                    ORDER BY rp.name ASC""", ( tuple(ids3), )
711
 
                           )
712
 
                dat = cr.dictfetchall()
713
 
                res = [lins for lins in partner_obj.browse(cr, uid, [
714
 
                                                           li['id'] for li in dat], context=context)]
715
 
        return res
716
 
    def _get_number_customer_portfolio(self, cr, uid, ids, fy, period,
717
 
                                                                context=None):
718
 
        ifrs_brw = self.browse(cr, uid, ids, context=context)
719
 
        company_id = ifrs_brw.ifrs_id.company_id.id
720
 
        if context.get('whole_fy', False):
721
 
            period_fy = [('period_id.fiscalyear_id', '=', fy),
722
 
                            ('period_id.special', '=', False)]
723
 
        else:
724
 
            period_fy = [('period_id', '=', period)]
725
 
        invoice_obj = self.pool.get('account.invoice')
726
 
        invoice_ids = invoice_obj.search(cr, uid, [
727
 
                                ('type', '=', 'out_invoice'),
728
 
                                ('state', 'in', ('open', 'paid',)),
729
 
                                ('company_id', '=', company_id)] + period_fy)
730
 
        partner_number = set([inv.partner_id.id for inv\
731
 
            in invoice_obj.browse(cr, uid, invoice_ids, context=context)])
732
 
        return len(list(partner_number))
733
 
 
734
 
    def onchange_sequence(self, cr, uid, ids, sequence, context=None):
735
 
        context = context or {}
736
 
        return {'value' : {'priority' : sequence}}
737
 
 
738
 
    def _get_default_sequence(self, cr, uid, context=None):
739
 
        ctx = context or {}
740
 
        res = 0
741
 
        if ctx.get('ifrs_id'):
742
 
            ifrs_lines_ids = self.search(cr, uid ,
743
 
                    [('ifrs_id','=',ctx['ifrs_id'])])
744
 
            if ifrs_lines_ids:
745
 
                res = max([line['sequence'] for line in self.read(cr,
746
 
                    uid, ifrs_lines_ids, ['sequence'])])
747
 
        return res + 10
748
 
    
749
 
    _columns = {
750
 
        'help': fields.related('ifrs_id','help', string='Show Help',type='boolean',help='Allows you to show the help in the form'),
751
 
        # Really!!! A repeated field with same functionality! This was done due
752
 
        # to the fact that web view everytime that sees sequence tries to allow
753
 
        # you to change the values and this feature here is undesirable.
754
 
        'priority': fields.related('sequence', string='Sequence', type='integer', store=True, help='Indicates the order of the line in the report. The sequence must be unique and unrepeatable'),
755
 
        'sequence': fields.integer('Sequence', required=True, help='Indicates the order of the line in the report. The sequence must be unique and unrepeatable'),
756
 
        'name': fields.char('Name', 128, required=True, translate=True, help='Line name in the report. This name can be translatable, if there are multiple languages loaded it can be translated'),
757
 
        'type': fields.selection(
758
 
            [
759
 
                ('abstract', 'Abstract'),
760
 
                ('detail', 'Detail'),
761
 
                ('constant', 'Constant'),
762
 
                ('total', 'Total')],
763
 
            string='Type',
764
 
            required=True,
765
 
            help='Line type of report:'
766
 
            " -Abstract(A),-Detail(D),-Constant(C),-Total(T)"),
767
 
        'constant_type': fields.selection(
768
 
            [
769
 
                ('period_days', 'Days of Period'),
770
 
                ('fy_periods', "FY's Periods"),
771
 
                ('fy_month', "FY's Month"),
772
 
                ('number_customer', "Number of customers* in portfolio")
773
 
            ],
774
 
            string='Constant Type',
775
 
            required=False,
776
 
            help='Constant Type'),
777
 
        'ifrs_id': fields.many2one('ifrs.ifrs', 'IFRS', required=True),
778
 
        'company_id': fields.related('ifrs_id', 'company_id', type='many2one',
779
 
            relation='res.company', string='Company', store=True),
780
 
        'amount': fields.float(string='Amount', help=("This field will update "
781
 
            "when you click the compute button in the IFRS doc form"),
782
 
            readonly=True),
783
 
        'cons_ids': fields.many2many('account.account', 'ifrs_account_rel', 'ifrs_lines_id', 'account_id', string='Consolidated Accounts'),
784
 
        'analytic_ids': fields.many2many('account.analytic.account', 'ifrs_analytic_rel', 'ifrs_lines_id', 'analytic_id', string='Consolidated Analytic Accounts'),
785
 
        'parent_id': fields.many2one('ifrs.lines', 'Parent', select=True, ondelete='set null', domain="[('ifrs_id','=',parent.id), ('type','=','total'),('id','!=',id)]"),
786
 
        'parent_abstract_id': fields.many2one('ifrs.lines', 'Parent Abstract', select=True, ondelete='set null', domain="[('ifrs_id','=',parent.id),('type','=','abstract'),('id','!=',id)]"),
787
 
        'parent_right': fields.integer('Parent Right', select=1),
788
 
        'parent_left': fields.integer('Parent Left', select=1),
789
 
        'level': fields.function(_get_level, string='Level', method=True, type='integer',
790
 
                                 store={
791
 
                                 'ifrs.lines': (_get_children_and_total, ['parent_id'], 10),
792
 
                                 }),
793
 
        'operand_ids': fields.many2many('ifrs.lines', 'ifrs_operand_rel',
794
 
            'ifrs_parent_id', 'ifrs_child_id', string='Second Operand'),
795
 
        'operator': fields.selection([
796
 
            ('subtract', 'Subtraction'),
797
 
            ('percent', 'Percentage'),
798
 
            ('ratio', 'Ratio'),
799
 
            ('product', 'Product'),
800
 
            ('without', 'First Operand Only')
801
 
        ],
802
 
            'Operator', required=False,
803
 
            help='Leaving blank will not take into account Operands'),
804
 
        'comparison': fields.selection([
805
 
            ('subtract', 'Subtraction'),
806
 
            ('percent', 'Percentage'),
807
 
            ('ratio', 'Ratio'),
808
 
            ('without', 'No Comparison')],
809
 
            'Make Comparison', required=False,
810
 
            help='Make a Comparison against the previous period.\nThat is, period X(n) minus period X(n-1)\nLeaving blank will not make any effects'),
811
 
        'acc_val': fields.selection([
812
 
            ('init', 'Initial Values'),
813
 
            ('var', 'Variation in Periods'),
814
 
            ('fy', ('Ending Values'))],
815
 
            'Accounting Span', required=False,
816
 
            help='Leaving blank means YTD'),
817
 
        'value': fields.selection([
818
 
            ('debit', 'Debit'),
819
 
            ('credit', 'Credit'),
820
 
            ('balance', 'Balance')],
821
 
            'Accounting Value', required=False,
822
 
            help='Leaving blank means Balance'),
823
 
        'total_ids': fields.many2many('ifrs.lines', 'ifrs_lines_rel', 'parent_id', 'child_id', string='First Operand'),
824
 
        'inv_sign': fields.boolean('Change Sign to Amount', help='Allows a change of sign'),
825
 
        'invisible': fields.boolean('Invisible', help='Allows whether the line of the report is printed or not'),
826
 
        'comment': fields.text('Comments/Question', help='Comments or questions about this ifrs line'),
827
 
        'ytd': fields.float('YTD', help='amount control field, functions to prevent repeated computes'),
828
 
        'period_1': fields.float('Periodo 1', help='1st period amount control field, functions to prevent repeated computes'),
829
 
        'period_2': fields.float('Periodo 2', help='2nd period amount control field, functions to prevent repeated computes'),
830
 
        'period_3': fields.float('Periodo 3', help='3rd period amount control field, functions to prevent repeated computes'),
831
 
        'period_4': fields.float('Periodo 4', help='4th period amount control field, functions to prevent repeated computes'),
832
 
        'period_5': fields.float('Periodo 5', help='5th period amount control field, functions to prevent repeated computes'),
833
 
        'period_6': fields.float('Periodo 6', help='6th period amount control field, functions to prevent repeated computes'),
834
 
        'period_7': fields.float('Periodo 7', help='7th period amount control field, functions to prevent repeated computes'),
835
 
        'period_8': fields.float('Periodo 8', help='8th period amount control field, functions to prevent repeated computes'),
836
 
        'period_9': fields.float('Periodo 9', help='9th period amount control field, functions to prevent repeated computes'),
837
 
        'period_10': fields.float('Periodo 10', help='10th period amount control field, functions to prevent repeated computes'),
838
 
        'period_11': fields.float('Periodo 11', help='11th period amount control field, functions to prevent repeated computes'),
839
 
        'period_12': fields.float('Periodo 12', help='12th period amount control field, functions to prevent repeated computes'),
840
 
    }
841
 
 
842
 
    _defaults = {
843
 
        'type': 'abstract',
844
 
        'invisible': False,
845
 
        'acc_val': 'fy',
846
 
        'value': 'balance',
847
 
        'help': lambda s, c, u, cx: cx.get('ifrs_help',True),
848
 
        'operator': 'without',
849
 
        'comparison': 'without',
850
 
        'sequence': _get_default_sequence,
851
 
        'priority': _get_default_sequence,
852
 
    }
853
 
 
854
 
    def _check_description(self, cr, user, ids,context=None):
855
 
        context = context or {}
856
 
        for s in self.browse(cr, user, ids):
857
 
            # if s.type=='total' and s.parent_id.type!='abstract':
858
 
            #    return False
859
 
            pass
860
 
        return True
861
 
 
862
 
    _constraints = [
863
 
        (_check_description, (
864
 
            'Error: Los padres de las lineas ifrs de tipo total solo pueden tener padres de tipo abstract'), ['parent_id']),
865
 
    ]
866
 
 
867
 
    _sql_constraints = [('sequence_ifrs_id_unique', 'unique(sequence,id)',
868
 
                         'The sequence already have been set in another IFRS line')]
869
 
 
870
 
ifrs_lines()
871
 
 
872
 
 
873
 
 
874
 
 
875
 
#~ pregunta. comprobacion de la linea... lo hace cuando le da a guardar--- no lo hace a la hora de ingresarlo, puede taer confuciones a la hora que el usuario agregue a mucha gente y luego no sepa a cual se refiere.
876
 
 
877
 
#~ buscar, como hacer para que ordene por secuencia, lo que ingreso!