~noviat/openobject-addons/extra-6.0

« back to all changes in this revision

Viewing changes to account_cashflow/account_cashflow.py

  • Committer: root
  • Date: 2012-04-10 20:37:39 UTC
  • Revision ID: root@oerp61-20120410203739-flykplw8jzpqa15c
update noviat v6.0 accounting modules

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- encoding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    OpenERP, Open Source Management Solution
 
5
#    
 
6
#    Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved.
 
7
 
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.
 
12
#
 
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.
 
17
#
 
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/>.
 
20
#
 
21
##############################################################################
 
22
 
 
23
import time
 
24
from datetime import datetime, date, timedelta
 
25
import tools
 
26
from osv import osv, fields
 
27
import decimal_precision as dp
 
28
import netsvc
 
29
logger=netsvc.Logger()
 
30
from tools.translate import _
 
31
 
 
32
class account_cashflow_code(osv.osv):  
 
33
    _name = 'account.cashflow.code'
 
34
    _description = 'Cash Flow Code'
 
35
    _order = 'sequence,type desc,code'
 
36
    
 
37
    def format_date(self, cr, uid, date, context):
 
38
        ''' format date according to language from context '''
 
39
        if not context:
 
40
            return date
 
41
        lang = context.get('lang')
 
42
        lang_obj = self.pool.get('res.lang')
 
43
        lang_id = lang_obj.search(cr, uid, [('code','=',lang)])[0]
 
44
        date_format = str(lang_obj.browse(cr, uid, lang_id).date_format)
 
45
        return date.strftime(date_format)
 
46
 
 
47
    def _balance_period(self, cr, uid, ids, field_name=None, arg=None, context=None, date_start=None, date_stop=None, day=None):
 
48
        #logger.notifyChannel('addons.' + self._name, netsvc.LOG_WARNING, '_balance_period, ids = %s' % (ids)) 
 
49
        if context is None:
 
50
            context = {}
 
51
        if not date_start:
 
52
            date_start = context.get('date_start', None)
 
53
        if not date_stop:
 
54
            date_stop = context.get('date_stop', None)
 
55
        company_id = context.get('company_id', self.pool.get('res.users').browse(cr, uid, uid, context).company_id.id,)
 
56
 
 
57
        if day:
 
58
            date_start = day        
 
59
            cr.execute('SELECT cashflow_code_id, balance FROM account_cashflow_balance WHERE date = %s', (day,))
 
60
        elif date_start:
 
61
            cr.execute('SELECT cashflow_code_id, sum(balance) FROM account_cashflow_balance ' \
 
62
                'WHERE date >= %s AND date <= %s GROUP BY cashflow_code_id',
 
63
                (date_start, date_stop))            
 
64
        else:
 
65
            cr.execute('SELECT id, 0.0 as amount FROM account_cashflow_code ')
 
66
        res=dict(cr.fetchall())
 
67
       
 
68
        # calculate period balance
 
69
        balopen_obj = self.pool.get('account.cashflow.opening.balance')
 
70
        balance_init_id = context.get('balance_init_id', None)
 
71
        if date_start:
 
72
            cr.execute("SELECT date FROM account_cashflow_opening_balance \
 
73
                WHERE date < %s AND active=TRUE AND company_id = %s ORDER BY date DESC LIMIT 1", 
 
74
                (date_start, company_id))
 
75
            res_date_open = cr.fetchone()
 
76
            date_open = res_date_open[0]
 
77
            cr.execute("SELECT balance FROM account_cashflow_opening_balance \
 
78
                WHERE date = %s AND active=TRUE AND company_id = %s", 
 
79
                (date_open, company_id))
 
80
            res_balance_open = cr.fetchone()
 
81
            balance_open = res_balance_open[0]
 
82
            cr.execute('SELECT sum(balance) FROM account_cashflow_balance ' \
 
83
                'WHERE date >= %s and date < %s', (date_open, date_start))
 
84
            sum_balance = cr.fetchone()
 
85
            res_init = (sum_balance[0] or 0.0) + balance_open           
 
86
            # recalculate opening balance for each day in order to support chart 'reload' actions after move update
 
87
            if day:
 
88
                balopen_obj.calc_opening_balance(cr, uid, date_start, balance_init_id, company_id)
 
89
            balance_init = {balance_init_id: res_init}
 
90
        else:
 
91
            balance_init = {balance_init_id: 0.0}            
 
92
        res.update(balance_init)    
 
93
 
 
94
        dp = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')        
 
95
        res2 = {}
 
96
        def _rec_get(record):
 
97
            amount = res.get(record.id, 0.0)
 
98
            for rec in record.child_ids:
 
99
                amount += _rec_get(rec) * rec.parent_sign
 
100
            return amount
 
101
        for record in self.browse(cr, uid, ids, context=context):
 
102
            res2[record.id] = round(_rec_get(record), dp)
 
103
        return res2
 
104
 
 
105
    def _balance_day(self, cr, uid, ids, field_name, arg, context):
 
106
        if context is None:
 
107
            context = {}
 
108
        day = None
 
109
        if context.get('date_start', None):
 
110
            date_start = context.get('date_start')
 
111
            nbr_days = int(context.get('nbr_days'))
 
112
            x = int(field_name[-2:])
 
113
            if x == 1:
 
114
                day = date_start                
 
115
            elif x <= nbr_days:
 
116
                day = (datetime.strptime(date_start, '%Y-%m-%d').date() + timedelta(days = int(field_name[-2:])-1)).isoformat()
 
117
        return self._balance_period(cr, uid, ids, field_name, arg, context, day=day)
 
118
 
 
119
    def fields_get(self, cr, uid, fields=None, context=None):
 
120
        res = super(account_cashflow_code, self).fields_get(cr, uid, fields, context)
 
121
        # remove type='provision' from selection list when configuring Cash Flow Codes
 
122
        if context.get('manage_cfc') and res.get('type'):
 
123
            res['type']['selection'].remove(('provision', u'Provision'))
 
124
        # rename date fields
 
125
        format_date = self.format_date
 
126
        if context.has_key('date_start'):
 
127
            date_start = datetime.strptime(context.get('date_start'), '%Y-%m-%d').date()            
 
128
            nbr_days = int(context.get('nbr_days'))
 
129
            days = [format_date(cr, uid, date_start, context)] + [format_date(cr, uid, date_start + timedelta(days=x), context) for x in range(1, nbr_days)]        
 
130
            for x in range(1, nbr_days + 1):
 
131
                if x < 10:
 
132
                    field = 'balance_day0' + str(x)
 
133
                else:
 
134
                    field = 'balance_day' + str(x)
 
135
                if res.get(field, None):
 
136
                    res[field]['string'] = days[x-1]
 
137
        return res
 
138
 
 
139
    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
 
140
        res = super(account_cashflow_code, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=False)
 
141
        if context.has_key('nbr_days'):
 
142
            nbr_days = int(context.get('nbr_days'))            
 
143
            for x in range(nbr_days+1,43):
 
144
                if x < 10:
 
145
                    field = 'balance_day0' + str(x)
 
146
                else:
 
147
                    field = 'balance_day' + str(x)
 
148
#                res['arch'] = res['arch'].replace('name="' + field + '"', 'name="' + field + '" invisible="1"')
 
149
                res['arch'] = res['arch'].replace('<field name="' + field + '"', '')        
 
150
        return res
 
151
 
 
152
    _columns = {
 
153
        'name': fields.char('Description', size=128, required=True, translate=True),
 
154
        'code': fields.char('Code', size=16, required=True),
 
155
        'type': fields.selection([
 
156
            ('view', 'View'),
 
157
            ('normal', 'Normal'),
 
158
            ('provision', 'Provision'),            
 
159
            ('init', 'Init'), 
 
160
        ], 'Type', required=True,
 
161
            help="Please ensure to have exactly one code of type 'Init' as placeholder for the Initial Balance."),
 
162
        'twin_id': fields.many2one('account.cashflow.code', 'Twin Code', domain=[('type','in',['normal', 'provision'])], ondelete='cascade',
 
163
            help="Twin code to reconcile provision lines with transaction lines."),
 
164
        'sequence': fields.integer('Sequence', required=True),        
 
165
        'balance_period': fields.function(_balance_period, method=True, string='Period Balance',
 
166
            help='Balance of the transactions over the selected period. The Valuta Date is used to calculate the balance'),
 
167
 
 
168
        'balance_day01': fields.function(_balance_day, method=True, string='Day 1'),
 
169
        'balance_day02': fields.function(_balance_day, method=True, string='Day 2'),
 
170
        'balance_day03': fields.function(_balance_day, method=True, string='Day 3'),
 
171
        'balance_day04': fields.function(_balance_day, method=True, string='Day 4'),
 
172
        'balance_day05': fields.function(_balance_day, method=True, string='Day 5'),
 
173
        'balance_day06': fields.function(_balance_day, method=True, string='Day 6'),
 
174
        'balance_day07': fields.function(_balance_day, method=True, string='Day 7'),
 
175
 
 
176
        'balance_day08': fields.function(_balance_day, method=True, string='Day 8'),
 
177
        'balance_day09': fields.function(_balance_day, method=True, string='Day 9'),
 
178
        'balance_day10': fields.function(_balance_day, method=True, string='Day 10'),
 
179
        'balance_day11': fields.function(_balance_day, method=True, string='Day 11'),
 
180
        'balance_day12': fields.function(_balance_day, method=True, string='Day 12'),
 
181
        'balance_day13': fields.function(_balance_day, method=True, string='Day 13'),
 
182
        'balance_day14': fields.function(_balance_day, method=True, string='Day 14'),
 
183
 
 
184
        'balance_day15': fields.function(_balance_day, method=True, string='Day 15'),
 
185
        'balance_day16': fields.function(_balance_day, method=True, string='Day 16'),
 
186
        'balance_day17': fields.function(_balance_day, method=True, string='Day 17'),
 
187
        'balance_day18': fields.function(_balance_day, method=True, string='Day 18'),
 
188
        'balance_day19': fields.function(_balance_day, method=True, string='Day 19'),
 
189
        'balance_day20': fields.function(_balance_day, method=True, string='Day 20'),
 
190
        'balance_day21': fields.function(_balance_day, method=True, string='Day 21'),
 
191
 
 
192
        'balance_day22': fields.function(_balance_day, method=True, string='Day 22'),
 
193
        'balance_day23': fields.function(_balance_day, method=True, string='Day 23'),
 
194
        'balance_day24': fields.function(_balance_day, method=True, string='Day 24'),
 
195
        'balance_day25': fields.function(_balance_day, method=True, string='Day 25'),
 
196
        'balance_day26': fields.function(_balance_day, method=True, string='Day 26'),
 
197
        'balance_day27': fields.function(_balance_day, method=True, string='Day 27'),
 
198
        'balance_day28': fields.function(_balance_day, method=True, string='Day 28'),
 
199
 
 
200
        'balance_day29': fields.function(_balance_day, method=True, string='Day 29'),
 
201
        'balance_day30': fields.function(_balance_day, method=True, string='Day 30'),
 
202
        'balance_day31': fields.function(_balance_day, method=True, string='Day 31'),
 
203
        'balance_day32': fields.function(_balance_day, method=True, string='Day 32'),
 
204
        'balance_day33': fields.function(_balance_day, method=True, string='Day 33'),
 
205
        'balance_day34': fields.function(_balance_day, method=True, string='Day 34'),
 
206
        'balance_day35': fields.function(_balance_day, method=True, string='Day 35'),
 
207
 
 
208
        'balance_day36': fields.function(_balance_day, method=True, string='Day 36'),
 
209
        'balance_day37': fields.function(_balance_day, method=True, string='Day 37'),
 
210
        'balance_day38': fields.function(_balance_day, method=True, string='Day 38'),
 
211
        'balance_day39': fields.function(_balance_day, method=True, string='Day 39'),
 
212
        'balance_day40': fields.function(_balance_day, method=True, string='Day 40'),
 
213
        'balance_day41': fields.function(_balance_day, method=True, string='Day 41'),
 
214
        'balance_day42': fields.function(_balance_day, method=True, string='Day 42'),
 
215
 
 
216
        'parent_id': fields.many2one('account.cashflow.code', 'Parent Code', domain=[('type', '=', 'view')]),
 
217
        'child_ids': fields.one2many('account.cashflow.code', 'parent_id', 'Child Codes'),
 
218
        'st_line_ids': fields.one2many('account.cashflow.line', 'cashflow_code_id', 'Bank Statement Lines'),
 
219
        'parent_sign': fields.float('Multiplier for Parent Code', required=True, 
 
220
            help='You can specify here the coefficient that will be used when consolidating the amount of this code into its parent. Set this value to 1 except for the top level Cash FLow Codes (Company and Total Balance).'),
 
221
        'active': fields.boolean('Active'),
 
222
        'company_id': fields.many2one('res.company', 'Company', required=True),   
 
223
    }
 
224
    _defaults = {
 
225
        'active': True,
 
226
        'type': 'normal',
 
227
        'parent_sign': 1.0,         
 
228
        'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 
229
    }
 
230
    _sql_constraints = [
 
231
        ('code_company_uniq', 'unique (code, type, company_id)', 'The code must be unique per company !'),
 
232
    ]
 
233
 
 
234
    def onchange_parent_id(self, cr, uid, ids, parent_id, context=None):
 
235
        parent = self.browse(cr, uid, parent_id, context=context)
 
236
        return {'value': {'sequence': parent.sequence}}
 
237
 
 
238
    def copy(self, cr, uid, id, default=None, context=None):
 
239
        cfc = self.browse(cr, uid, id, context=context)
 
240
        if not default:
 
241
            default = {}
 
242
        default = default.copy()
 
243
        default.update({'st_line_ids': []})
 
244
        default['code'] = cfc.code + ' (copy)'
 
245
        return super(account_cashflow_code, self).copy(cr, uid, id, default, context) 
 
246
    
 
247
    def name_get(self, cr, uid, ids, context=None):
 
248
        if not ids:
 
249
            return []
 
250
        reads = self.read(cr, uid, ids, ['name', 'code'], context=context)
 
251
        res = []
 
252
        for record in reads:
 
253
            if context.get('cashflow_code_name_get', False) == 'code':
 
254
                name = record['code']
 
255
            else:
 
256
                name = record['code'] + ' ' + record['name']
 
257
            res.append((record['id'], name))
 
258
        return res
 
259
 
 
260
    def name_search(self, cr, user, name, args=None, operator='ilike', context=None, limit=100):
 
261
        if not args:
 
262
            args = []
 
263
        ids = []
 
264
        if name:
 
265
            ids = self.search(cr, user, [('code', operator, name + '%')] + args, limit=limit)
 
266
            if not ids:
 
267
                ids = self.search(cr, user, [('name', operator, name)] + args, limit=limit)
 
268
            if not ids and len(name.split()) >= 2:
 
269
                #Separating code and name for searching
 
270
                operand1, operand2 = name.split(' ', 1) #name can contain spaces
 
271
                ids = self.search(cr, user, [('code', '=like', operand1), ('name', operator, operand2)] + args, limit=limit)
 
272
        else:
 
273
            ids = self.search(cr, user, args, context=context, limit=limit)
 
274
        return self.name_get(cr, user, ids, context=context)
 
275
 
 
276
    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
 
277
        #logger.notifyChannel('addons.' + self._name, netsvc.LOG_WARNING, 'search, args = %s' % (args)) 
 
278
        if context is None:
 
279
            context = {}
 
280
        elif context.get('search_origin') == 'account.cashflow.line.overview':
 
281
            # do not override search args when called from 'account.cashflow.line.overview'
 
282
            pass
 
283
        elif context.has_key('date_start'):
 
284
            # remove empty lines when called from Cash Flow Chart
 
285
            move_cfc_ids = self.search(cr, uid, [('type', 'not in', ['normal', 'provision'])])
 
286
            cr.execute('SELECT b.cashflow_code_id, min(b.balance), max(b.balance) FROM account_cashflow_balance b ' \
 
287
                'INNER JOIN account_cashflow_code c on b.cashflow_code_id=c.id ' \
 
288
                'WHERE b.date >= %s AND b.date <= %s AND c.type IN (\'normal\',\'provision\') AND c.active = TRUE ' \
 
289
                'GROUP BY cashflow_code_id',
 
290
                (context['date_start'], context['date_stop']))  
 
291
            res=cr.dictfetchall()
 
292
            for cfc in res:
 
293
                if not (cfc['min'] == cfc['max'] == 0.0): 
 
294
                    move_cfc_ids += [cfc['cashflow_code_id']]
 
295
            args += [('id', 'in', move_cfc_ids)]
 
296
        return super(account_cashflow_code, self).search(cr, uid, args, offset, limit, order, context, count)
 
297
 
 
298
    def create(self, cr, uid, vals, context=None):
 
299
        if context is None:
 
300
            context = {}
 
301
        res_id = super(account_cashflow_code, self).create(cr, uid, vals, context=context)
 
302
        cfc_type = vals.get('type')
 
303
        if cfc_type in ['normal', 'provision'] and not context.get('create_cfc_twin'):
 
304
            twin_vals = vals.copy()
 
305
            twin_vals['type'] = cfc_type == 'normal' and 'provision' or 'normal'
 
306
            twin_vals['twin_id'] = res_id
 
307
            twin_id = self.create(cr, uid, twin_vals, context={'create_cfc_twin': 1})
 
308
            if not twin_id:
 
309
                raise osv.except_osv('Error', _("Configuration Error !"))
 
310
            self.write(cr, uid, [res_id], {'twin_id': twin_id}, context={'create_cfc_twin': 1})
 
311
        return res_id
 
312
 
 
313
    def write(self, cr, uid, ids, vals, context={}):
 
314
        unlink_ids = []
 
315
        if not context.get('create_cfc_twin') and not context.get('update_cfc_twin'):
 
316
            for cfc in self.browse(cr, uid, ids, context=context):
 
317
                if cfc.type in ['normal', 'provision']:
 
318
                    twin_vals = vals.copy()
 
319
                    if twin_vals.get('type'):
 
320
                        twin_vals['type'] = cfc.type == 'normal' and 'provision' or 'normal'
 
321
                    self.write(cr, uid, [cfc.twin_id.id], twin_vals, context={'update_cfc_twin': 1})
 
322
                else:
 
323
                    twin_id = cfc.twin_id
 
324
                    if twin_id:
 
325
                        vals['twin_id'] = None
 
326
                        unlink_ids.append(twin_id.id)
 
327
        res = super(account_cashflow_code, self).write(cr, uid, ids, vals, context)
 
328
        self.unlink(cr, uid, unlink_ids)
 
329
        return res
 
330
    
 
331
 
 
332
account_cashflow_code()
 
333
 
 
334
class account_cashflow_rule(osv.osv):
 
335
    _name = 'account.cashflow.rule'
 
336
    _description = 'Rules Engine to assign Cash Flow Codes'
 
337
    _order = 'sequence'
 
338
    _columns = {
 
339
        'name': fields.char('Rule Name', size=128, required=True),                
 
340
        'sequence': fields.integer('Sequence', help='Determines the order of the rules to assign Cash Flow Codes'),
 
341
        'cashflow_code_id': fields.many2one('account.cashflow.code', 'Cash Flow Code', required=True),
 
342
        'sign': fields.selection([
 
343
            ('debit', 'Debit'),
 
344
            ('credit', 'Credit'),
 
345
            ], 'Movement Sign',
 
346
            help='Sign for the Cash Flow Code Assignment'),
 
347
        'journal_id': fields.many2one('account.journal', 'Journal', ondelete='cascade', domain=[('type', 'in', ['bank', 'cash'])]),
 
348
        'account_id': fields.many2one('account.account', 'Account', ondelete='cascade', domain=[('type', '!=', 'view')]),
 
349
        'partner_id': fields.many2one('res.partner', 'Partner', ondelete='cascade'),
 
350
        'active': fields.boolean('Active', help='Switch off this rule.'),
 
351
        'company_id': fields.many2one('res.company', 'Company', required=True),
 
352
    }
 
353
    _defaults = {
 
354
        'active': True,                 
 
355
        'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 
356
    }
 
357
    def cfc_id_get(self, cr, uid, sign=None, account_id=None, journal_id=None, partner_id=None, 
 
358
                   extra_fields={}, company_id=None, context=None):       
 
359
        ''' 
 
360
        The extra_fields dictionary (extra_fields = {fieldname1: value1, field_name2: value2, ... )) 
 
361
        allows addition of customer specific criteria via inheritance:
 
362
        - add extra fields (fieldname1, fieldname2, ... ) to account.cashflow.rule;
 
363
        - add extra_fields to the context ('extra_fields': [ (fieldname1, value1, operand1), (fieldname2, value2, operand2), ... ] ) of the create() method of account.bank.statement.line.
 
364
        '''
 
365
 
 
366
        extra_select = ''
 
367
        base_condition = '(not rule[1] or (sign == rule[1])) and (not rule[2] or (journal_id == rule[2])) ' \
 
368
            'and (not rule[3] or (account_id == rule[3])) and (not rule[4] or (partner_id == rule[4])) '
 
369
        index = 4        
 
370
        extra_condition = ''
 
371
        for x in extra_fields:
 
372
            extra_select += ', %s' % x[0]
 
373
            value = x[1]
 
374
            operand = x[2]
 
375
            index += 1
 
376
            if isinstance(value, str) or isinstance(value, unicode):
 
377
                extra_condition += "and (not rule[%s] or ('%s' %s rule[%s])) " % (index, value, operand, index)
 
378
            else:    
 
379
                extra_condition += "and (not rule[%s] or (%s %s rule[%s])) " % (index, value, operand, index)
 
380
        cr.execute('SELECT cashflow_code_id, sign, journal_id, account_id, partner_id%s ' \
 
381
            'FROM account_cashflow_rule ' \
 
382
            'WHERE active = TRUE AND company_id = %s ' \
 
383
            'ORDER BY sequence' % (extra_select, company_id)
 
384
        )
 
385
        rules = cr.fetchall()    
 
386
        cfc_id = None
 
387
        condition = base_condition + extra_condition
 
388
        for rule in rules:
 
389
            if eval(condition):
 
390
                cfc_id = rule[0]
 
391
                break
 
392
        return cfc_id
 
393
 
 
394
account_cashflow_rule()
 
395
 
 
396
class account_cashflow_provision_line(osv.osv):
 
397
 
 
398
    def _get_reference_model(self, cr, uid, context=None):
 
399
        res = [('account.invoice', 'Invoice / Credit Note')] 
 
400
        return res
 
401
 
 
402
    _order = 'val_date desc, journal_id'
 
403
    _name = 'account.cashflow.provision.line'
 
404
    _description = 'Cash Flow Provision Line'    
 
405
    _columns = {
 
406
        # general fields
 
407
        'description': fields.char('Description', size=64, states={'confirm': [('readonly', True)]}),
 
408
        'cashflow_code_id': fields.many2one('account.cashflow.code', 'Cash Flow Code', required=True, 
 
409
            domain=[('type', '=', 'provision')], states={'confirm': [('readonly', True)]}),
 
410
        'date': fields.date('Entry Date', required=True, readonly=True),
 
411
        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed')],
 
412
            'State', required=True, readonly=True),    
 
413
        'update_date': fields.date('Update Date', required=True, readonly=True),
 
414
        'update_by': fields.many2one('res.users', 'Updated by', required=True, readonly=True),        
 
415
        'note': fields.text('Notes', states={'confirm': [('readonly', True)]}),
 
416
        # originating transaction fields
 
417
        'origin': fields.reference('Originating Transaction', size=128, readonly=True,
 
418
            selection=_get_reference_model,
 
419
            help='This field contains a reference to the transaction that originated the creation of this provision.'),
 
420
        # reconciliation lookup fields
 
421
        'journal_id': fields.many2one('account.journal', 'Journal', domain=[('type', '=', 'bank')], 
 
422
            states={'confirm': [('readonly', True)]}),
 
423
        'val_date': fields.date('Valuta Date', required=True, states={'confirm': [('readonly', True)]}),   
 
424
        'amount': fields.float('Amount', digits_compute=dp.get_precision('Account'), required=True, states={'confirm': [('readonly', True)]}),
 
425
        'partner_id': fields.many2one('res.partner', 'Partner', states={'confirm': [('readonly', True)]}),
 
426
        'name': fields.char('Communication', size=64, states={'confirm': [('readonly', True)]}),
 
427
        'payment_reference': fields.char('Payment Reference', size=35, states={'confirm': [('readonly', True)]},
 
428
            help="Payment Reference. For SEPA (SCT or SDD) transactions, the PaymentInformationIdentification " \
 
429
                 "is recorded in this field pertaining to a globalisation, and the EndToEndReference for " \
 
430
                 "simple transactions or for the details of a globalisation."),       
 
431
        'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True),
 
432
        # reconciliation result fields
 
433
        'cfc_normal_id': fields.related('cashflow_code_id', 'twin_id', type='many2one', 
 
434
            relation='account.cashflow.code', string='Reconcile Code', readonly=True),
 
435
        'type': fields.selection([
 
436
            ('supplier','Supplier'),
 
437
            ('customer','Customer'),
 
438
            ('general','General')
 
439
            ], 'Type', states={'confirm': [('readonly', True)]}),
 
440
        'account_id': fields.many2one('account.account','Account', domain=[('type', '<>', 'view')], 
 
441
            states={'confirm': [('readonly', True)]}),
 
442
        'cfline_partial_ids': fields.one2many('account.cashflow.line', 'cfpline_rec_partial_id', 'Partially Reconciled Cash Flow Lines'),
 
443
    }
 
444
    _defaults = {
 
445
        'date': lambda *a: time.strftime('%Y-%m-%d'),
 
446
        'update_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
 
447
        'update_by': lambda s, c, u, ctx: u,
 
448
        'state': 'draft',
 
449
        'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 
450
    }
 
451
 
 
452
    def write(self, cr, uid, ids, vals, context={}):
 
453
        cfbalance_obj = self.pool.get('account.cashflow.balance')        
 
454
        for pline in self.browse(cr, uid, ids, context):    
 
455
            # update account_cashflow_balance for changes on cashflow provision lines
 
456
            if vals.get('cashflow_code_id', False) or vals.get('val_date', False) or vals.get('amount', False):
 
457
                old_cfc_id = pline.cashflow_code_id.id or None
 
458
                new_cfc_id = vals.get('cashflow_code_id', old_cfc_id)
 
459
                old_val_date = pline.val_date
 
460
                new_val_date = vals.get('val_date', old_val_date)
 
461
                old_amount = pline.amount
 
462
                new_amount = vals.get('amount', old_amount)
 
463
                if old_cfc_id != new_cfc_id or old_val_date != new_val_date or old_amount != new_amount:
 
464
                    values = {
 
465
                        'old_cfc_id': old_cfc_id,
 
466
                        'new_cfc_id': new_cfc_id,
 
467
                        'old_val_date': old_val_date,
 
468
                        'new_val_date': new_val_date,
 
469
                        'old_amount': old_amount,                        
 
470
                        'new_amount': new_amount,
 
471
                    }
 
472
                    cfbalance_obj.update_balance(cr, uid, values)
 
473
        vals['update_date'] = time.strftime('%Y-%m-%d %H:%M:%S')
 
474
        vals['update_by'] = uid
 
475
        return super(account_cashflow_provision_line, self).write(cr, uid, ids, vals, context)       
 
476
     
 
477
    def create(self, cr, uid, vals, context=None):
 
478
        cfbalance_obj = self.pool.get('account.cashflow.balance')
 
479
        # update Cash Flow Balances table
 
480
        if vals.get('cashflow_code_id'): 
 
481
            values = {
 
482
                'old_cfc_id': False,
 
483
                'new_cfc_id': vals.get('cashflow_code_id'),
 
484
                'old_val_date': False,
 
485
                'new_val_date': vals.get('val_date'),
 
486
                'old_amount': False,
 
487
                'new_amount': vals['amount'],                    
 
488
            }
 
489
            cfbalance_obj.update_balance(cr, uid, values)
 
490
        return super(account_cashflow_provision_line, self).create(cr, uid, vals, context=context) 
 
491
    
 
492
    def unlink(self, cr, uid, ids, context=None):
 
493
        cfbalance_obj = self.pool.get('account.cashflow.balance')       
 
494
        for pline in self.browse(cr, uid, ids, context):  
 
495
            if pline.state == 'confirm':
 
496
                raise osv.except_osv('Warning', _('Delete operation not allowed !'))
 
497
            values = {
 
498
                'old_cfc_id': pline.cashflow_code_id.id,
 
499
                'new_cfc_id': False,
 
500
                'old_val_date': pline.val_date,
 
501
                'new_val_date': False,
 
502
                'old_amount': pline.amount,
 
503
                'new_amount': False,                    
 
504
            }
 
505
            cfbalance_obj.update_balance(cr, uid, values)   
 
506
        return super(account_cashflow_provision_line, self).unlink(cr, uid, ids, context=context)
 
507
         
 
508
account_cashflow_provision_line()
 
509
 
 
510
class account_cashflow_line(osv.osv):
 
511
    _name = 'account.cashflow.line'
 
512
    _description = 'Cash Flow Line'
 
513
    _inherits = {'account.bank.statement.line': 'st_line_id'}
 
514
    _columns = {
 
515
        'st_line_id': fields.many2one('account.bank.statement.line', 'Bank Statement Line', ondelete='cascade', 
 
516
            required=True, states={'confirm': [('readonly', True)]}),
 
517
        'cashflow_code_id': fields.many2one('account.cashflow.code', 'Cash Flow Code', 
 
518
            domain=[('type', '=', 'normal')], states={'confirm': [('readonly', True)]}),
 
519
        'cfpline_rec_partial_id': fields.many2one('account.cashflow.provision.line', 'Partially Reconciled Provision Line', readonly=True, ondelete='set null'),
 
520
    }
 
521
 
 
522
    def onchange_type(self, cr, uid, line_id, partner_id, type, context=None):
 
523
        return self.pool.get('account.bank.statement.line').onchange_type(cr, uid, line_id, partner_id, type, context=None)
 
524
 
 
525
    def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
 
526
        return self.pool.get('account.bank.statement.line').onchange_partner_id(cr, uid, ids, partner_id, context=None)
 
527
 
 
528
    def write(self, cr, uid, ids, vals, context={}):
 
529
        cfbalance_obj = self.pool.get('account.cashflow.balance')
 
530
        for cfline in self.browse(cr, uid, ids, context):    
 
531
            old_cfc_id = cfline.cashflow_code_id.id or False
 
532
            # update embedded account.bank.statement.line first via super().write
 
533
            # changes to val_date and amount will result in updated balances via the write method of the embedded object
 
534
            super(account_cashflow_line, self).write(cr, uid, cfline.id, vals, context) 
 
535
            # update account_cashflow_balance
 
536
            if vals.has_key('cashflow_code_id'):
 
537
                new_cfc_id = vals['cashflow_code_id']
 
538
                if old_cfc_id != new_cfc_id:
 
539
                    values = {
 
540
                        'old_cfc_id': old_cfc_id,
 
541
                        'new_cfc_id': new_cfc_id,
 
542
                        'old_val_date': cfline.val_date,
 
543
                        'new_val_date': cfline.val_date,
 
544
                        'old_amount': cfline.amount,                        
 
545
                        'new_amount': cfline.amount,
 
546
                    }
 
547
                    cfbalance_obj.update_balance(cr, uid, values)
 
548
        return True
 
549
 
 
550
    def unlink(self, cr, uid, ids, context=None):
 
551
        if context is None:
 
552
            context = {}
 
553
        if context.get('block_cashflow_line_delete', False):
 
554
            raise osv.except_osv('Warning', _('Delete operation not allowed ! \
 
555
                Please go to the associated bank statement in order to delete and/or modify this line'))
 
556
        return super(account_cashflow_line, self).unlink(cr, uid, ids, context=context)
 
557
   
 
558
    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
 
559
        if context is None:
 
560
            context = {}
 
561
        if context.get('active_model', False) == 'account.cashflow.code':
 
562
            cfc_obj = self.pool.get('account.cashflow.code')
 
563
            cfc_id = context.get('active_id', 0)
 
564
            cfc = cfc_obj.browse(cr, uid, cfc_id, context=context)
 
565
            def _ids_get(record):
 
566
                ids = [record.id]
 
567
                if record.type == 'view':
 
568
                    for child in record.child_ids:
 
569
                        ids += _ids_get(child)
 
570
                return ids
 
571
            cfc_ids = _ids_get(cfc)
 
572
            date_start = context.get('date_start', time.strftime('%Y-%m-%d'))
 
573
            date_stop = context.get('date_stop', time.strftime('%Y-%m-%d'))
 
574
            args += [('cashflow_code_id', 'in', cfc_ids), ('val_date', '>=', date_start), ('val_date', '<=', date_stop) ]
 
575
        return super(account_cashflow_line, self).search(cr, uid, args, offset, limit, order, context, count)   
 
576
 
 
577
    def view_header_get(self, cr, uid, view_id, view_type, context=None):
 
578
        if context is None:
 
579
            context = {}
 
580
        if context.get('active_model', False) == 'account.cashflow.code':
 
581
            format_date = self.pool.get('account.cashflow.code').format_date   
 
582
            cfc_id = context.get('active_id', 0)
 
583
            cfc_code = self.pool.get('account.cashflow.code').browse(cr, uid, cfc_id).code
 
584
            date_start = format_date(cr, uid, datetime.strptime(context['date_start'], '%Y-%m-%d').date(), context) 
 
585
            date_stop = format_date(cr, uid, datetime.strptime(context['date_stop'], '%Y-%m-%d').date(), context) 
 
586
            view_header = cfc_code + ': ' + date_start + '..' + date_stop
 
587
            return view_header
 
588
        return False
 
589
    
 
590
account_cashflow_line()
 
591
 
 
592
class account_cashflow_opening_balance(osv.osv):
 
593
    _name = 'account.cashflow.opening.balance'
 
594
    _description = 'Table to store Cash Flow opening balances'
 
595
    _order = 'date desc'
 
596
    
 
597
    _columns = {
 
598
        'date': fields.date('Valuta Date', required=True, states={'confirm': [('readonly', True)]}),
 
599
        'balance': fields.float('Opening balance', digits_compute=dp.get_precision('Account'), required=True, states={'confirm': [('readonly', True)]}),
 
600
        'active': fields.boolean('Active', required=True, states={'confirm': [('readonly', True)]}),
 
601
        'company_id': fields.many2one('res.company', 'Company', required=True, states={'confirm': [('readonly', True)]}),   
 
602
        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed')],
 
603
            'State', required=True, readonly=True),    
 
604
    }
 
605
    _defaults = {
 
606
        'active': True,
 
607
        'state': 'draft',
 
608
        'balance': 0.0,         
 
609
        'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 
610
    }
 
611
    def unlink(self, cr, uid, ids, context=None):        
 
612
        for balance in self.read(cr, uid, ids, ['state'], context=context):
 
613
            if balance['state'] == 'confirm':
 
614
                raise osv.except_osv('Warning', _('Delete operation not allowed !'))
 
615
        return super(account_cashflow_opening_balance, self).unlink(cr, uid, ids, context=context)
 
616
    
 
617
    def action_confirm(self, cr, uid, ids, context=None):
 
618
        self.write(cr, uid, ids, {'state':'confirm'})
 
619
        return True
 
620
 
 
621
    def action_draft(self, cr, uid, ids, context=None):
 
622
        self.write(cr, uid, ids, {'state':'draft'})
 
623
        return True
 
624
 
 
625
    def calc_opening_balance(self, cr, uid, date, balance_init_id, company_id):
 
626
        """
 
627
        Method to update account.cashflow.opening.balance table 
 
628
        Input parameters: 
 
629
            - date : valuta date
 
630
            - balance_init_id : id of the company's Cash Flow Code for the Initial Balance
 
631
            - company_id
 
632
        Calculation logic : opening balance = most recent opening balance plus moves prior to 'val_date'
 
633
        Returns : True
 
634
        """
 
635
        # find opening balance prior to 'val_date'
 
636
        cr.execute("SELECT date, balance FROM account_cashflow_opening_balance \
 
637
            WHERE date < %s AND active=TRUE AND company_id = %s ORDER BY date DESC LIMIT 1", 
 
638
            (date, company_id))
 
639
        res_open = cr.fetchone()
 
640
        if not res_open:
 
641
            raise osv.except_osv('Configuration Error', _("Please check if you have an active Opening Balance prior to the selected period !"))         
 
642
        date_open = res_open[0]
 
643
        balance_open = res_open[1]
 
644
        # calculate opening balance
 
645
        cr.execute('SELECT sum(balance) FROM account_cashflow_balance ' \
 
646
            'WHERE date >= %s and date < %s AND company_id = %s', (date_open, date, company_id))
 
647
        sum_balance = cr.fetchone()
 
648
        res_init = (sum_balance[0] or 0.0) + balance_open
 
649
        # update or create opening balance
 
650
        bal_ids = self.search(cr, uid, [('date', '=', date)])
 
651
        if bal_ids:
 
652
            self.write(cr, uid, bal_ids,
 
653
                {'date': date,
 
654
                 'balance': res_init,
 
655
                 'active': True,
 
656
                 'state': 'confirm'})
 
657
        else:
 
658
            self.create(cr, uid,
 
659
                {'date': date,
 
660
                 'balance': res_init,
 
661
                 'active': True,
 
662
                 'state': 'confirm'})       
 
663
        return True
 
664
    
 
665
account_cashflow_opening_balance()
 
666
 
 
667
class account_cashflow_balance(osv.osv):
 
668
    _name = 'account.cashflow.balance'
 
669
    _description = 'Table to store daily Cash Flow balances'
 
670
    _order = 'date desc'
 
671
    
 
672
    _columns = {
 
673
        'date': fields.date('Valuta Date', required=True, states={'confirm': [('readonly', True)]}),
 
674
        'cashflow_code_id': fields.many2one('account.cashflow.code', 'Cash Flow Code', domain=[('type', '=', 'normal')], required=True, states={'confirm': [('readonly', True)]}),
 
675
        'cfc_type': fields.related('cashflow_code_id', 'type', type='char', relation='account.cashflow.code', string='Type', readonly=True),
 
676
        'balance': fields.float('Balance', digits_compute=dp.get_precision('Account'), required=True, states={'confirm': [('readonly', True)]},
 
677
            help='Cumulative balance of all transactions till the entry date. The Valuta Date is used to calculate the balance'),
 
678
        'company_id': fields.many2one('res.company', 'Company', required=True, states={'confirm': [('readonly', True)]}),   
 
679
        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed')],
 
680
            'State', required=True, readonly=True),    
 
681
    }
 
682
    _defaults = {
 
683
        'balance': 0.0,         
 
684
        'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 
685
        'state': 'draft',
 
686
    }
 
687
 
 
688
    def unlink(self, cr, uid, ids, context=None):        
 
689
        for balance in self.read(cr, uid, ids, ['state'], context=context):
 
690
            if balance['state'] == 'confirm':
 
691
                raise osv.except_osv('Warning', _('Delete operation not allowed !'))
 
692
        return super(account_cashflow_balance, self).unlink(cr, uid, ids, context=context)
 
693
    
 
694
    def action_confirm(self, cr, uid, ids, context=None):
 
695
        self.write(cr, uid, ids, {'state':'confirm'})
 
696
        return True
 
697
 
 
698
    def action_draft(self, cr, uid, ids, context=None):
 
699
        self.write(cr, uid, ids, {'state':'draft'})
 
700
        return True
 
701
    
 
702
    def update_balance(self, cr, uid, values={}):
 
703
        """
 
704
        method to update account.cashflow.balance table 
 
705
        input : dictionary with keys old_cfc_id, old_val_date, old_amount, new_cfc_id, new_val_date, new_amount
 
706
        returns : True
 
707
        """
 
708
        old_cfc_id = values['old_cfc_id']
 
709
        new_cfc_id = values['new_cfc_id']
 
710
        old_val_date = values['old_val_date']
 
711
        new_val_date = values['new_val_date']
 
712
        old_amount = values['old_amount']
 
713
        new_amount = values['new_amount']
 
714
 
 
715
        # update old
 
716
        if old_cfc_id:
 
717
            old_ids = self.search(cr, uid, [('cashflow_code_id', '=', old_cfc_id), ('date', '=', old_val_date)])
 
718
            if old_ids:
 
719
                balance = self.read(cr, uid, old_ids[0], ['balance'])['balance'] 
 
720
                self.write(cr, uid, old_ids[0], {'balance': balance - old_amount, 'state': 'confirm'})
 
721
            else:
 
722
                cfc_obj = self.pool.get('account.cashflow.code')
 
723
                code = cfc_obj.browse(cr, uid, cfc_obj.search(cr, uid, [('id', '=', old_cfc_id)])[0]).code
 
724
                raise osv.except_osv('Missing Balance', _("Please recalculate your Cash Flow Balances or enter your Cash Flow Balance for Cash Flow Code '%s' on Valuta Date '%s' !") \
 
725
                    % (code, old_val_date))
 
726
            
 
727
        # update or create new
 
728
        if new_cfc_id:
 
729
            new_ids = self.search(cr, uid, [('cashflow_code_id', '=', new_cfc_id), ('date', '=', new_val_date)])
 
730
            if new_ids:
 
731
                balance = self.read(cr, uid, new_ids[0], ['balance'])['balance'] 
 
732
                self.write(cr, uid, new_ids[0], {'balance': balance + new_amount})
 
733
            else:
 
734
                self.create(cr, uid, {
 
735
                    'date': new_val_date,
 
736
                    'cashflow_code_id': new_cfc_id,
 
737
                    'balance': new_amount,
 
738
                    'state': 'confirm',
 
739
                    })
 
740
        return True
 
741
 
 
742
account_cashflow_balance()
 
743
 
 
744
class account_cashflow_line_overview(osv.osv):
 
745
    _name = 'account.cashflow.line.overview'
 
746
    _description = 'Cash Flow Lines Overview'
 
747
    _auto = False
 
748
    
 
749
    _columns = {
 
750
        'name': fields.char('Communication', size=64, readonly=True),
 
751
        'date': fields.date('Entry Date', readonly=True),
 
752
        'val_date': fields.date('Valuta Date', readonly=True),   
 
753
        'cashflow_code_id': fields.many2one('account.cashflow.code', 'Cash Flow Code', 
 
754
            states={'confirm': [('readonly', True)]}, context={'search_origin': _name}, 
 
755
            domain=[('type', '=', 'normal')]),
 
756
        'cashflow_type': fields.selection([
 
757
            ('normal','Normal'),
 
758
            ('provision','Provision'),
 
759
            ], 'Cash Flow Type', readonly=True),
 
760
        'amount': fields.float('Amount', digits_compute=dp.get_precision('Account'), readonly=True),
 
761
        'globalisation_id': fields.many2one('account.bank.statement.line.global', 'Globalisation ID', readonly=True),
 
762
        'globalisation_amount': fields.related('globalisation_id', 'amount', type='float', 
 
763
            relation='account.bank.statement.line.global', string='Glob. Amount', readonly=True),
 
764
        'journal_id': fields.many2one('account.journal', 'Journal', readonly=True),
 
765
        'type': fields.selection([
 
766
            ('supplier','Supplier'),
 
767
            ('customer','Customer'),
 
768
            ('general','General')
 
769
            ], 'Type', readonly=True),
 
770
        'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
 
771
        'account_id': fields.many2one('account.account','Account', domain=[('type', '!=', 'view')], readonly=True),
 
772
        'payment_reference': fields.char('Payment Reference', size=35, readonly=True),
 
773
        'note': fields.text('Notes', readonly=True),
 
774
        'company_id': fields.many2one('res.company', 'Company', readonly=True),
 
775
        'update_date': fields.date('Update Date', readonly=True),
 
776
        'update_by': fields.many2one('res.users', 'Updated by', readonly=True),        
 
777
        'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed')],
 
778
            'State', readonly=True),    
 
779
    }
 
780
 
 
781
    def init(self, cr):
 
782
        tools.drop_view_if_exists(cr, 'account_cashflow_line_overview')
 
783
        cr.execute("""
 
784
            CREATE OR REPLACE VIEW account_cashflow_line_overview AS (
 
785
            (SELECT
 
786
                c.id AS id,
 
787
                l.name AS name,                
 
788
                l.date AS date,
 
789
                l.val_date AS val_date,
 
790
                c.cashflow_code_id AS cashflow_code_id,
 
791
                'normal' AS cashflow_type,
 
792
                l.amount AS amount,
 
793
                l.globalisation_id AS globalisation_id,
 
794
                l.journal_id AS journal_id,
 
795
                l.type AS type,
 
796
                l.partner_id AS partner_id,
 
797
                l.account_id AS account_id,
 
798
                l.payment_reference AS payment_reference, 
 
799
                l.note AS note, 
 
800
                l.company_id AS company_id, 
 
801
                l.update_date AS update_date,
 
802
                l.update_by AS update_by, 
 
803
                l.state AS state
 
804
            FROM account_cashflow_line c 
 
805
            INNER JOIN account_bank_statement_line l ON (c.st_line_id=l.id) )
 
806
            UNION
 
807
            (SELECT
 
808
                -p.id AS id,
 
809
                p.name AS name,                
 
810
                p.date AS date,
 
811
                p.val_date AS val_date,
 
812
                p.cashflow_code_id AS cashflow_code_id,
 
813
                'provision' AS cashflow_type,
 
814
                p.amount AS amount,
 
815
                NULL AS globalisation_id,
 
816
                p.journal_id AS journal_id,
 
817
                p.type AS type,
 
818
                p.partner_id AS partner_id,
 
819
                p.account_id AS account_id,
 
820
                p.payment_reference AS payment_reference, 
 
821
                p.note AS note, 
 
822
                p.company_id AS company_id, 
 
823
                p.update_date AS update_date,
 
824
                p.update_by AS update_by, 
 
825
                p.state AS state
 
826
            FROM account_cashflow_provision_line p )
 
827
            );
 
828
            
 
829
        """)
 
830
 
 
831
    def create(self, cr, uid, vals, context=None):
 
832
        raise osv.except_osv('Warning', _('No record creation allowed from this screen.'))
 
833
        return super(account_cashflow_line_overview, self).create(cr, uid, vals, context=context) 
 
834
 
 
835
    def write(self, cr, uid, ids, vals, context={}):
 
836
        # limit updates to the casflow_code_id field
 
837
        cline_obj = self.pool.get('account.cashflow.line')                
 
838
        pline_obj = self.pool.get('account.cashflow.provision.line')
 
839
        cfc_obj = self.pool.get('account.cashflow.code')     
 
840
        for line in self.browse(cr, uid, ids, context):
 
841
            cfc_id = vals.get('cashflow_code_id')
 
842
            if cfc_id:
 
843
                cfc = cfc_obj.browse(cr, uid, cfc_id, context=context)
 
844
                if line.id < 0:
 
845
                    upd_obj = pline_obj 
 
846
                    upd_ids = [-line.id]
 
847
                    cfc_id = cfc.twin_id.id
 
848
                else:
 
849
                    upd_obj = cline_obj 
 
850
                    upd_ids = [line.id]                
 
851
                upd_obj.write(cr, uid, upd_ids, {'cashflow_code_id': cfc_id}, context=context)
 
852
        return True
 
853
 
 
854
    def unlink(self, cr, uid, ids, context=None):
 
855
        if context is None:
 
856
            context = {}
 
857
        for line_id in ids:
 
858
            if line_id > 0:
 
859
                return self.pool.get('account.cashflow.line').unlink(cr, uid, [line_id], context=context)
 
860
            else:
 
861
                return self.pool.get('account.cashflow.provision.line').unlink(cr, uid, [-line_id], context=context)
 
862
 
 
863
    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
 
864
        if context is None:
 
865
            context = {}
 
866
        if context.get('active_model', False) == 'account.cashflow.code':
 
867
            cfc_obj = self.pool.get('account.cashflow.code')
 
868
            cfc_id = context.get('active_id', 0)
 
869
            cfc = cfc_obj.browse(cr, uid, cfc_id, context=context)
 
870
            def _ids_get(record):
 
871
                if record.type in ['normal', 'provision']:
 
872
                    ids = [record.id, record.twin_id.id]
 
873
                else:
 
874
                    ids = []
 
875
                if record.type == 'view':
 
876
                    for child in record.child_ids:
 
877
                        ids += _ids_get(child)
 
878
                return ids
 
879
            cfc_ids = list(set(_ids_get(cfc)))            
 
880
            active_column = context.get('tree_but_open_column')
 
881
            if active_column and active_column[:11] == 'balance_day': 
 
882
                date_start = date_stop = context.get('active_day')
 
883
            else:
 
884
                date_start = context.get('date_start', time.strftime('%Y-%m-%d'))
 
885
                date_stop = context.get('date_stop', time.strftime('%Y-%m-%d'))
 
886
            args += [('cashflow_code_id', 'in', cfc_ids), ('val_date', '>=', date_start), ('val_date', '<=', date_stop)]
 
887
        return super(account_cashflow_line_overview, self).search(cr, uid, args, offset, limit, order, context, count)   
 
888
 
 
889
account_cashflow_line_overview()
 
890
        
 
 
b'\\ No newline at end of file'