~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to account_override/account.py

  • Committer: jf
  • Date: 2014-05-28 13:16:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2187.
  • Revision ID: jfb@tempo-consulting.fr-20140528131631-13qcl8f5h390rmtu
UFTP-244 [FIX] In sync context, do not auto create the link between account.account and account.destination.link for default destination
this link is created by a dedicated sync rule

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
from osv import osv
25
25
from osv import fields
 
26
from account_override import ACCOUNT_RESTRICTED_AREA
26
27
from tools.translate import _
27
28
from time import strftime
28
29
import datetime
 
30
from dateutil.relativedelta import relativedelta
 
31
import decimal_precision as dp
 
32
import netsvc
29
33
 
30
34
class account_account(osv.osv):
 
35
    '''
 
36
        To create a activity period, 2 new fields are created, and are NOT linked to the
 
37
        'active' field, since the behaviors are too different.
 
38
    '''
31
39
    _name = "account.account"
32
40
    _inherit = "account.account"
33
41
 
68
76
                arg.append(('inactivation_date', '<=', cmp_date))
69
77
        return arg
70
78
 
 
79
    #@@@override account.account_account.__compute
 
80
    def __compute(self, cr, uid, ids, field_names, arg=None, context=None,
 
81
                  query='', query_params=()):
 
82
        """ compute the balance, debit and/or credit for the provided
 
83
        account ids
 
84
        Arguments:
 
85
        `ids`: account ids
 
86
        `field_names`: the fields to compute (a list of any of
 
87
                       'balance', 'debit' and 'credit')
 
88
        `arg`: unused fields.function stuff
 
89
        `query`: additional query filter (as a string)
 
90
        `query_params`: parameters for the provided query string
 
91
                        (__compute will handle their escaping) as a
 
92
                        tuple
 
93
        """
 
94
        mapping = {
 
95
            'balance': "COALESCE(SUM(l.debit),0) " \
 
96
                       "- COALESCE(SUM(l.credit), 0) as balance",
 
97
            'debit': "COALESCE(SUM(l.debit), 0) as debit",
 
98
            'credit': "COALESCE(SUM(l.credit), 0) as credit"
 
99
        }
 
100
        #get all the necessary accounts
 
101
        children_and_consolidated = self._get_children_and_consol(cr, uid, ids, context=context)
 
102
        #compute for each account the balance/debit/credit from the move lines
 
103
        accounts = {}
 
104
        sums = {}
 
105
        # Add some query/query_params regarding context
 
106
        link = " "
 
107
        if context.get('currency_id', False):
 
108
            if query:
 
109
                link = " AND "
 
110
            query += link + 'currency_id = %s'
 
111
            query_params += tuple([context.get('currency_id')])
 
112
        link = " "
 
113
        if context.get('instance_ids', False):
 
114
            if query:
 
115
                link = " AND "
 
116
            instance_ids = context.get('instance_ids')
 
117
            if isinstance(instance_ids, (int, long)):
 
118
                instance_ids = [instance_ids]
 
119
            if len(instance_ids) == 1:
 
120
                query += link + 'l.instance_id = %s'
 
121
            else:
 
122
                query += link + 'l.instance_id in %s'
 
123
            query_params += tuple(instance_ids)
 
124
        # Do normal process
 
125
        if children_and_consolidated:
 
126
            aml_query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
 
127
 
 
128
            wheres = [""]
 
129
            if query.strip():
 
130
                wheres.append(query.strip())
 
131
            if aml_query.strip():
 
132
                wheres.append(aml_query.strip())
 
133
            filters = " AND ".join(wheres)
 
134
            # target_move from chart of account wizard
 
135
            filters = filters.replace("AND l.state <> 'draft'", '')
 
136
            prefilters = " "
 
137
            if context.get('move_state', False):
 
138
                prefilters += "AND l.move_id = m.id AND m.state = '%s'" % context.get('move_state')
 
139
            else:
 
140
                prefilters += "AND l.move_id = m.id AND m.state in ('posted', 'draft')"
 
141
            # Notifications
 
142
            self.logger.notifyChannel('account_override.'+self._name, netsvc.LOG_DEBUG,
 
143
                                      'Filters: %s'%filters)
 
144
            # IN might not work ideally in case there are too many
 
145
            # children_and_consolidated, in that case join on a
 
146
            # values() e.g.:
 
147
            # SELECT l.account_id as id FROM account_move_line l
 
148
            # INNER JOIN (VALUES (id1), (id2), (id3), ...) AS tmp (id)
 
149
            # ON l.account_id = tmp.id
 
150
            # or make _get_children_and_consol return a query and join on that
 
151
            request = ("SELECT l.account_id as id, " +\
 
152
                       ', '.join(map(mapping.__getitem__, field_names)) +
 
153
                       " FROM account_move_line l, account_move m" +\
 
154
                       " WHERE l.account_id IN %s " \
 
155
                            + prefilters + filters +
 
156
                       " GROUP BY l.account_id")
 
157
            params = (tuple(children_and_consolidated),) + query_params
 
158
            cr.execute(request, params)
 
159
            self.logger.notifyChannel('account_override.'+self._name, netsvc.LOG_DEBUG,
 
160
                                      'Status: %s'%cr.statusmessage)
 
161
 
 
162
            for res in cr.dictfetchall():
 
163
                accounts[res['id']] = res
 
164
 
 
165
            # consolidate accounts with direct children
 
166
            children_and_consolidated.reverse()
 
167
            brs = list(self.browse(cr, uid, children_and_consolidated, context=context))
 
168
            currency_obj = self.pool.get('res.currency')
 
169
            while brs:
 
170
                current = brs[0]
 
171
                brs.pop(0)
 
172
                for fn in field_names:
 
173
                    sums.setdefault(current.id, {})[fn] = accounts.get(current.id, {}).get(fn, 0.0)
 
174
                    for child in current.child_id:
 
175
                        if child.company_id.currency_id.id == current.company_id.currency_id.id:
 
176
                            sums[current.id][fn] += sums[child.id][fn]
 
177
                        else:
 
178
                            sums[current.id][fn] += currency_obj.compute(cr, uid, child.company_id.currency_id.id, current.company_id.currency_id.id, sums[child.id][fn], context=context)
 
179
        res = {}
 
180
        null_result = dict((fn, 0.0) for fn in field_names)
 
181
        company_currency = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id.id
 
182
        for i in ids:
 
183
            res[i] = sums.get(i, null_result)
 
184
            # If output_currency_id in context, we change computation
 
185
            for f_name in ('debit', 'credit', 'balance'):
 
186
                if context.get('output_currency_id', False) and res[i].get(f_name, False):
 
187
                    new_amount = currency_obj.compute(cr, uid, context.get('output_currency_id'), company_currency, res[i].get(f_name), context=context)
 
188
                    res[i][f_name] = new_amount
 
189
        return res
 
190
    #@@@end
 
191
 
 
192
    def _get_restricted_area(self, cr, uid, ids, field_name, args, context=None):
 
193
        """
 
194
        FAKE METHOD
 
195
        """
 
196
        # Check
 
197
        if context is None:
 
198
            context = {}
 
199
        res = {}
 
200
        for account_id in ids:
 
201
            res[account_id] = True
 
202
        return res
 
203
 
 
204
    def _search_restricted_area(self, cr, uid, ids, name, args, context=None):
 
205
        """
 
206
        Search the right domain to apply to this account filter.
 
207
        For this, it uses the "ACCOUNT_RESTRICTED_AREA" variable in which we list all well-known cases.
 
208
        The key args is "restricted_area", the param is like "register_lines".
 
209
        In ACCOUNT_RESTRICTED_AREA, we use the param as key. It so return the domain to apply.
 
210
        If no domain, return an empty domain.
 
211
        """
 
212
        # Check
 
213
        if context is None:
 
214
            context = {}
 
215
        arg = []
 
216
        for x in args:
 
217
            if x[0] == 'restricted_area' and x[2]:
 
218
                if x[2] in ACCOUNT_RESTRICTED_AREA:
 
219
                    for subdomain in ACCOUNT_RESTRICTED_AREA[x[2]]:
 
220
                        arg.append(subdomain)
 
221
            elif x[0] != 'restricted_area':
 
222
                arg.append(x)
 
223
            else:
 
224
                raise osv.except_osv(_('Error'), _('Operation not implemented!'))
 
225
        return arg
 
226
 
 
227
    def _get_fake_cash_domain(self, cr, uid, ids, field_name, arg, context=None):
 
228
        """
 
229
        Fake method for domain
 
230
        """
 
231
        if context is None:
 
232
            context = {}
 
233
        res = {}
 
234
        for cd_id in ids:
 
235
            res[cd_id] = True
 
236
        return res
 
237
 
 
238
    def _search_cash_domain(self, cr, uid, ids, field_names, args, context=None):
 
239
        """
 
240
        Return a given domain (defined in ACCOUNT_RESTRICTED_AREA variable)
 
241
        """
 
242
        if context is None:
 
243
            context = {}
 
244
        arg = []
 
245
        for x in args:
 
246
            if x[0] and x[1] == '=' and x[2]:
 
247
                if x[2] in ['cash', 'bank', 'cheque']:
 
248
                    arg.append(('restricted_area', '=', 'journals'))
 
249
            else:
 
250
                raise osv.except_osv(_('Error'), _('Operation not implemented!'))
 
251
        return arg
 
252
 
 
253
    def _get_is_specific_counterpart(self, cr, uid, ids, field_names, args, context=None):
 
254
        """
 
255
        If this account is the same as default intermission counterpart OR rebilling intersection account, then return True. Otherwise return nothing.
 
256
        """
 
257
        # Checks
 
258
        if context is None:
 
259
            context = {}
 
260
        # Prepare some values
 
261
        res = {}
 
262
        account = False
 
263
        if field_names == 'is_intermission_counterpart':
 
264
            account = self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart
 
265
        elif field_names == 'is_intersection_counterpart':
 
266
            account = self.pool.get('res.users').browse(cr, uid, uid).company_id.import_invoice_default_account
 
267
        specific_account_id = account and account.id or False
 
268
 
 
269
        for account_id in ids:
 
270
            res[account_id] = False
 
271
        if specific_account_id in ids:
 
272
            res[specific_account_id] = True
 
273
        return res
 
274
 
 
275
    def _search_is_specific_counterpart(self, cr, uid, ids, field_names, args, context=None):
 
276
        """
 
277
        Return the intermission counterpart OR the rebilling intersection account ID.
 
278
        """
 
279
        # Checks
 
280
        if context is None:
 
281
            context = {}
 
282
        # Prepare some values
 
283
        arg = []
 
284
        account = False
 
285
        fieldname = False
 
286
        if field_names == 'is_intermission_counterpart':
 
287
            account = self.pool.get('res.users').browse(cr, uid, uid).company_id.intermission_default_counterpart
 
288
            fieldname = 'intermission_default_counterpart'
 
289
        elif field_names == 'is_intersection_counterpart':
 
290
            account = self.pool.get('res.users').browse(cr, uid, uid).company_id.import_invoice_default_account
 
291
            fieldname = 'import_invoice_default_account'
 
292
        specific_account_id = account and account.id or False
 
293
 
 
294
        for x in args:
 
295
            if x[0] == field_names and x[2] is True:
 
296
                if specific_account_id:
 
297
                    arg.append(('id', '=', specific_account_id))
 
298
            elif x[0] == field_names and x[2] is False:
 
299
                if specific_account_id:
 
300
                    arg.append(('id', '!=', specific_account_id))
 
301
            elif x[0] != field_names:
 
302
                arg.append(x)
 
303
            else:
 
304
                raise osv.except_osv(_('Error'), _('Filter on field %s not implemented! %s') % (field_names, x,))
 
305
        return arg
 
306
 
71
307
    _columns = {
72
308
        'name': fields.char('Name', size=128, required=True, select=True, translate=True),
73
 
        'type_for_register': fields.selection([('none', 'None'), ('transfer', 'Internal Transfer'), ('transfer_same','Internal Transfer (same currency)'), 
 
309
        'activation_date': fields.date('Active from', required=True),
 
310
        'inactivation_date': fields.date('Inactive from'),
 
311
        'note': fields.char('Note', size=160),
 
312
        'type_for_register': fields.selection([('none', 'None'), ('transfer', 'Internal Transfer'), ('transfer_same','Internal Transfer (same currency)'),
74
313
            ('advance', 'Operational Advance'), ('payroll', 'Third party required - Payroll'), ('down_payment', 'Down payment'), ('donation', 'Donation')], string="Type for specific treatment", required=True,
75
 
            help="""This permit to give a type to this account that impact registers. In fact this will link an account with a type of element 
76
 
            that could be attached. For an example make the account to be a transfer type will display only registers to the user in the Cash Register 
 
314
            help="""This permit to give a type to this account that impact registers. In fact this will link an account with a type of element
 
315
            that could be attached. For an example make the account to be a transfer type will display only registers to the user in the Cash Register
77
316
            when he add a new register line.
78
317
            """),
79
 
        'is_settled_at_hq': fields.boolean("Settled at HQ"),
 
318
        'shrink_entries_for_hq': fields.boolean("Shrink entries for HQ export", help="Check this attribute if you want to consolidate entries on this account before they are exported to the HQ system."),
80
319
        'filter_active': fields.function(_get_active, fnct_search=_search_filter_active, type="boolean", method=True, store=False, string="Show only active accounts",),
 
320
        'restricted_area': fields.function(_get_restricted_area, fnct_search=_search_restricted_area, type='boolean', method=True, string="Is this account allowed?"),
 
321
        'cash_domain': fields.function(_get_fake_cash_domain, fnct_search=_search_cash_domain, method=True, type='boolean', string="Domain used to search account in journals", help="This is only to change domain in journal's creation."),
 
322
        'balance': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Balance', multi='balance'),
 
323
        'debit': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Debit', multi='balance'),
 
324
        'credit': fields.function(__compute, digits_compute=dp.get_precision('Account'), method=True, string='Credit', multi='balance'),
 
325
        'is_intermission_counterpart': fields.function(_get_is_specific_counterpart, fnct_search=_search_is_specific_counterpart, method=True, type='boolean', string='Is the intermission counterpart account?'),
 
326
        'is_intersection_counterpart': fields.function(_get_is_specific_counterpart, fnct_search=_search_is_specific_counterpart, method=True, type='boolean', string='Is the intersection counterpart account?'),
81
327
    }
82
328
 
83
329
    _defaults = {
 
330
        'activation_date': lambda *a: (datetime.datetime.today() + relativedelta(months=-3)).strftime('%Y-%m-%d'),
84
331
        'type_for_register': lambda *a: 'none',
85
 
        'is_settled_at_hq': lambda *a: False,
 
332
        'shrink_entries_for_hq': lambda *a: True,
86
333
    }
87
334
 
 
335
    # UTP-493: Add a dash between code and account name
 
336
    def name_get(self, cr, uid, ids, context=None):
 
337
        """
 
338
        Use "-" instead of " " between name and code for account's default name
 
339
        """
 
340
        if not ids:
 
341
            return []
 
342
        reads = self.read(cr, uid, ids, ['name', 'code'], context=context)
 
343
        res = []
 
344
        for record in reads:
 
345
            name = record['name']
 
346
            if record['code']:
 
347
                name = record['code'] + ' - '+name
 
348
            res.append((record['id'], name))
 
349
        return res
 
350
 
 
351
    def _get_parent_of(self, cr, uid, ids, limit=10, context=None):
 
352
        """
 
353
        Get all parents from the given accounts.
 
354
        To avoid problem of recursion, set a limit from 1 to 10.
 
355
        """
 
356
        # Some checks
 
357
        if context is None:
 
358
            context = {}
 
359
        if not ids:
 
360
            return []
 
361
        if isinstance(ids, (int, long)):
 
362
            ids = [ids]
 
363
        if limit < 1 or limit > 10:
 
364
            raise osv.except_osv(_('Error'), _("You're only allowed to use a limit between 1 and 10."))
 
365
        # Prepare some values
 
366
        account_ids = list(ids)
 
367
        sql = """
 
368
            SELECT parent_id
 
369
            FROM account_account
 
370
            WHERE id IN %s
 
371
            AND parent_id IS NOT NULL
 
372
            GROUP BY parent_id"""
 
373
        cr.execute(sql, (tuple(ids),))
 
374
        if not cr.rowcount:
 
375
            return account_ids
 
376
        parent_ids = [x[0] for x in cr.fetchall()]
 
377
        account_ids += parent_ids
 
378
        stop = 1
 
379
        while parent_ids:
 
380
            # Stop the search if we reach limit
 
381
            if stop >= limit:
 
382
                break
 
383
            stop += 1
 
384
            cr.execute(sql, (tuple(parent_ids),))
 
385
            if not cr.rowcount:
 
386
                parent_ids = False
 
387
            tmp_res = cr.fetchall()
 
388
            tmp_ids = [x[0] for x in tmp_res]
 
389
            if None in tmp_ids:
 
390
                parent_ids = False
 
391
            else:
 
392
                parent_ids = list(tmp_ids)
 
393
                account_ids += tmp_ids
 
394
        return account_ids
 
395
 
 
396
    def _check_date(self, vals, context=None):
 
397
        if context is None:
 
398
            context = {}
 
399
 
 
400
        if 'inactivation_date' in vals and vals['inactivation_date'] is not False:
 
401
            if vals['inactivation_date'] <= datetime.date.today().strftime('%Y-%m-%d') and not context.get('sync_update_execution', False):
 
402
                # validate the date (must be > today)
 
403
                raise osv.except_osv(_('Warning !'), _('You cannot set an inactivity date lower than tomorrow!'))
 
404
            elif 'activation_date' in vals and not vals['activation_date'] < vals['inactivation_date']:
 
405
                # validate that activation date
 
406
                raise osv.except_osv(_('Warning !'), _('Activation date must be lower than inactivation date!'))
 
407
 
 
408
    def create(self, cr, uid, vals, context=None):
 
409
        self._check_date(vals, context=context)
 
410
        return super(account_account, self).create(cr, uid, vals, context=context)
 
411
 
 
412
    def write(self, cr, uid, ids, vals, context=None):
 
413
        self._check_date(vals, context=context)
 
414
        return super(account_account, self).write(cr, uid, ids, vals, context=context)
 
415
 
 
416
    def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
 
417
        """
 
418
        Filtering regarding context
 
419
        """
 
420
        if not context:
 
421
            context = {}
 
422
        if context.get('filter_inactive_accounts'):
 
423
            args.append(('activation_date', '<=', datetime.date.today().strftime('%Y-%m-%d')))
 
424
            args.append('|')
 
425
            args.append(('inactivation_date', '>', datetime.date.today().strftime('%Y-%m-%d')))
 
426
            args.append(('inactivation_date', '=', False))
 
427
        return super(account_account, self).search(cr, uid, args, offset, limit, order, context=context, count=count)
 
428
 
88
429
account_account()
89
430
 
90
431
class account_journal(osv.osv):
 
432
    _name = 'account.journal'
91
433
    _inherit = 'account.journal'
92
434
 
93
435
    # @@@override account>account.py>account_journal>create_sequence
109
451
            'code': code,
110
452
            'active': True,
111
453
            'prefix': '',
112
 
            'padding': 6,
 
454
            'padding': 4,
113
455
            'number_increment': 1
114
456
        }
115
457
        return seq_pool.create(cr, uid, seq)
116
 
    
 
458
 
117
459
account_journal()
118
460
 
119
461
class account_move(osv.osv):
127
469
 
128
470
    _columns = {
129
471
        'name': fields.char('Entry Sequence', size=64, required=True),
130
 
        'statement_line_ids': fields.many2many('account.bank.statement.line', 'account_bank_statement_line_move_rel', 'statement_id', 'move_id', 
 
472
        'statement_line_ids': fields.many2many('account.bank.statement.line', 'account_bank_statement_line_move_rel', 'statement_id', 'move_id',
131
473
            string="Statement lines", help="This field give all statement lines linked to this move."),
132
474
        'ref': fields.char('Reference', size=64, readonly=True, states={'draft':[('readonly',False)]}),
133
475
        'status': fields.selection([('sys', 'system'), ('manu', 'manual')], string="Status", required=True),
136
478
        'document_date': fields.date('Document Date', size=255, required=True, help="Used for manual journal entries"),
137
479
        'journal_type': fields.related('journal_id', 'type', type='selection', selection=_journal_type_get, string="Journal Type", \
138
480
            help="This indicates which Journal Type is attached to this Journal Entry"),
 
481
        'sequence_id': fields.many2one('ir.sequence', string='Lines Sequence', ondelete='cascade',
 
482
            help="This field contains the information related to the numbering of the lines of this journal entry."),
139
483
    }
140
484
 
141
485
    _defaults = {
174
518
                raise osv.except_osv(_('Error'), _('Posting date should be include in defined Period%s.') % (m.period_id and ': ' + m.period_id.name or '',))
175
519
        return True
176
520
 
 
521
    def _hook_check_move_line(self, cr, uid, move_line, context=None):
 
522
        """
 
523
        Check date on move line. Should be the same as Journal Entry (account.move)
 
524
        """
 
525
        if not context:
 
526
            context = {}
 
527
        res = super(account_move, self)._hook_check_move_line(cr, uid, move_line, context=context)
 
528
        if not move_line:
 
529
            return res
 
530
        if move_line.date != move_line.move_id.date:
 
531
            raise osv.except_osv(_('Error'), _("Journal item does not have same posting date (%s) as journal entry (%s).") % (move_line.date, move_line.move_id.date))
 
532
        return res
 
533
 
 
534
    def create_sequence(self, cr, uid, vals, context=None):
 
535
        """
 
536
        Create new entry sequence for every new journal entry
 
537
        """
 
538
        seq_pool = self.pool.get('ir.sequence')
 
539
        seq_typ_pool = self.pool.get('ir.sequence.type')
 
540
 
 
541
        name = 'Journal Items L' # For Journal Items Lines
 
542
        code = 'account.move'
 
543
 
 
544
        types = {
 
545
            'name': name,
 
546
            'code': code
 
547
        }
 
548
        seq_typ_pool.create(cr, uid, types)
 
549
 
 
550
        seq = {
 
551
            'name': name,
 
552
            'code': code,
 
553
            'prefix': '',
 
554
            'padding': 0,
 
555
        }
 
556
        return seq_pool.create(cr, uid, seq)
 
557
 
177
558
    def create(self, cr, uid, vals, context=None):
178
559
        """
179
560
        Change move line's sequence (name) by using instance move prefix.
184
565
        # Change the name for (instance_id.move_prefix) + (journal_id.code) + sequence number
185
566
        instance = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.instance_id
186
567
        journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'])
187
 
        sequence_number = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id)
188
 
        if instance and journal and sequence_number and ('name' not in vals or vals['name'] == '/'):
189
 
            if not instance.move_prefix:
190
 
                raise osv.except_osv(_('Warning'), _('No move prefix found for this instance! Please configure it on Company view.'))
191
 
            vals['name'] = "%s-%s-%s" % (instance.move_prefix, journal.code, sequence_number)
192
568
        # Add default date and document date if none
193
569
        if not vals.get('date', False):
194
570
            vals.update({'date': self.pool.get('account.period').get_date_in_period(cr, uid, strftime('%Y-%m-%d'), vals.get('period_id'))})
201
577
                context['document_date'] = vals.get('document_date')
202
578
            if 'date' in vals:
203
579
                context['date'] = vals.get('date')
 
580
 
 
581
        if context.get('seqnums',False):
 
582
            # utp913 - reuse sequence numbers if in the context
 
583
            vals['name'] = context['seqnums'][journal.id]
 
584
        else:
 
585
            # Create sequence for move lines
 
586
            period_ids = self.pool.get('account.period').get_period_from_date(cr, uid, vals['date'])
 
587
            if not period_ids:
 
588
                raise osv.except_osv(_('Warning'), _('No period found for creating sequence on the given date: %s') % (vals['date'] or ''))
 
589
            period = self.pool.get('account.period').browse(cr, uid, period_ids)[0]
 
590
            # Context is very important to fetch the RIGHT sequence linked to the fiscalyear!
 
591
            sequence_number = self.pool.get('ir.sequence').get_id(cr, uid, journal.sequence_id.id, context={'fiscalyear_id': period.fiscalyear_id.id})
 
592
            if instance and journal and sequence_number and ('name' not in vals or vals['name'] == '/'):
 
593
                if not instance.move_prefix:
 
594
                    raise osv.except_osv(_('Warning'), _('No move prefix found for this instance! Please configure it on Company view.'))
 
595
                vals['name'] = "%s-%s-%s" % (instance.move_prefix, journal.code, sequence_number)
 
596
 
 
597
        # Create a sequence for this new journal entry
 
598
        res_seq = self.create_sequence(cr, uid, vals, context)
 
599
        vals.update({'sequence_id': res_seq,})
 
600
        # Default behaviour (create)
204
601
        res = super(account_move, self).create(cr, uid, vals, context=context)
205
602
        self._check_document_date(cr, uid, res, context)
206
603
        self._check_date_in_period(cr, uid, res, context)
216
613
        """
217
614
        if not context:
218
615
            context = {}
219
 
        if context.get('from_web_menu', False) or context.get('sync_data', False):
 
616
        if context.get('from_web_menu', False) or context.get('sync_update_execution', False):
220
617
            # by default, from synchro, we just need to update period_id and journal_id
221
618
            fields = ['journal_id', 'period_id']
222
619
            # from web menu, we also update document_date and date
227
624
                    raise osv.except_osv(_('Warning'), _('You cannot edit a Journal Entry created by the system.'))
228
625
                # Update context in order journal item could retrieve this @creation
229
626
                # Also update some other fields
 
627
                ml_vals = {}
230
628
                for el in fields:
231
629
                    if el in vals:
232
630
                        context[el] = vals.get(el)
233
 
                        for ml in m.line_id:
234
 
                            self.pool.get('account.move.line').write(cr, uid, ml.id, {el: vals.get(el)}, context, False, False)
 
631
                        ml_vals.update({el: vals.get(el)})
 
632
                # Update document date AND date at the same time
 
633
                if ml_vals:
 
634
                    for ml in m.line_id:
 
635
                        self.pool.get('account.move.line').write(cr, uid, ml.id, ml_vals, context, False, False)
235
636
        res = super(account_move, self).write(cr, uid, ids, vals, context=context)
236
637
        self._check_document_date(cr, uid, ids, context)
237
638
        self._check_date_in_period(cr, uid, ids, context)
259
660
        """
260
661
        if not context:
261
662
            context = {}
262
 
        for id in ids:
263
 
            ml_ids = self.pool.get('account.move.line').search(cr, uid, [('move_id', '=', id)])
 
663
        for i in ids:
 
664
            ml_ids = self.pool.get('account.move.line').search(cr, uid, [('move_id', '=', i)])
264
665
            if not ml_ids:
265
666
                raise osv.except_osv(_('Warning'), _('No line found. Please add some lines before Journal Entry validation!'))
266
667
        if context.get('from_web_menu', False):
267
668
            for m in self.browse(cr, uid, ids):
268
669
                if m.status == 'sys':
269
670
                    raise osv.except_osv(_('Warning'), _('You are not able to approve a Journal Entry that comes from the system!'))
 
671
                # UFTP-105: Do not permit to validate a journal entry on a period that is not open
 
672
                if m.period_id and m.period_id.state != 'draft':
 
673
                    raise osv.except_osv(_('Warning'), _('You cannot post entries in a non-opened period: %s') % (m.period_id.name))
270
674
                prev_currency_id = False
271
675
                for ml in m.line_id:
272
676
                    if not prev_currency_id:
276
680
                        raise osv.except_osv(_('Warning'), _('You cannot have two different currencies for the same Journal Entry!'))
277
681
        return super(account_move, self).button_validate(cr, uid, ids, context=context)
278
682
 
 
683
    def copy(self, cr, uid, a_id, default={}, context=None):
 
684
        """
 
685
        Copy a manual journal entry
 
686
        """
 
687
        if not context:
 
688
            context = {}
 
689
        context.update({'omit_analytic_distribution': False})
 
690
        je = self.browse(cr, uid, [a_id], context=context)[0]
 
691
        if je.status == 'sys' or (je.journal_id and je.journal_id.type == 'migration'):
 
692
            raise osv.except_osv(_('Error'), _("You can only duplicate manual journal entries."))
 
693
        vals = {
 
694
            'line_id': [],
 
695
            'state': 'draft',
 
696
            'document_date': je.document_date,
 
697
            'date': je.date,
 
698
            'name': ''
 
699
        }
 
700
        res = super(account_move, self).copy(cr, uid, id, vals, context=context)
 
701
        for line in je.line_id:
 
702
            self.pool.get('account.move.line').copy(cr, uid, line.id, {'move_id': res, 'document_date': je.document_date, 'date': je.date, 'period_id': je.period_id and je.period_id.id or False}, context)
 
703
        self.validate(cr, uid, [res], context=context)
 
704
        return res
 
705
 
279
706
    def onchange_journal_id(self, cr, uid, ids, journal_id=False, context=None):
280
707
        """
281
708
        Change some fields when journal is changed.
323
750
 
324
751
class account_move_reconcile(osv.osv):
325
752
    _inherit = 'account.move.reconcile'
326
 
    
 
753
 
327
754
    def get_name(self, cr, uid, context=None):
328
755
        instance = self.pool.get('res.users').browse(cr, uid, uid, context).company_id.instance_id
329
756
        sequence_number = self.pool.get('ir.sequence').get(cr, uid, 'account.move.reconcile')
334
761
 
335
762
    _columns = {
336
763
        'name': fields.char('Entry Sequence', size=64, required=True),
337
 
        'statement_line_ids': fields.many2many('account.bank.statement.line', 'account_bank_statement_line_move_rel', 'statement_id', 'move_id', 
 
764
        'statement_line_ids': fields.many2many('account.bank.statement.line', 'account_bank_statement_line_move_rel', 'statement_id', 'move_id',
338
765
            string="Statement lines", help="This field give all statement lines linked to this move."),
339
766
    }
340
767
    _defaults = {
342
769
    }
343
770
 
344
771
account_move_reconcile()
 
772
 
 
773
class account_account_type(osv.osv):
 
774
    _name = 'account.account.type'
 
775
    _inherit = 'account.account.type'
 
776
 
 
777
    _columns = {
 
778
        'not_correctible': fields.boolean(string="Prevent entries to be correctible on this account type.")
 
779
    }
 
780
 
 
781
    _defaults = {
 
782
        'not_correctible': lambda *a: False,
 
783
    }
 
784
 
 
785
account_account_type()
345
786
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: