~openerp-spain-team/openerp-spain/6.0-git

« back to all changes in this revision

Viewing changes to l10n_es/l10n_ES_cierre_ejercicio/fyc.py

  • Committer: Borja L.S.
  • Date: 2010-10-18 10:04:25 UTC
  • Revision ID: git-v1:271c47a993616dbba60585d48b8b98d603199d93
[REF] *: Refactorización para portar a 6.0 - Paso 1.

- Se han renombrado los módulos para usar la nomenclatura propuesta
  por OpenERP: l10n_es para el módulo base de localización (plan de 
  cuentas), l10n_es_* para el resto de módulos.

- Se eliminan los módulos extra_addons/* que deberían moverse a 
  los extra-addons genéricos (no son específicos de España).

- Se renombran los __terp__.py por __openerp__.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
# -*- encoding: utf-8 -*-
3
 
##############################################################################
4
 
#
5
 
#    OpenERP, Open Source Management Solution
6
 
#    Copyright (C) 2010 Pexego Sistemas Informáticos. All Rights Reserved
7
 
#    $Id$
8
 
#
9
 
#    This program is free software: you can redistribute it and/or modify
10
 
#    it under the terms of the GNU General Public License as published by
11
 
#    the Free Software Foundation, either version 3 of the License, or
12
 
#    (at your option) any later version.
13
 
#
14
 
#    This program is distributed in the hope that it will be useful,
15
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
#    GNU General Public License for more details.
18
 
#
19
 
#    You should have received a copy of the GNU General Public License
20
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
#
22
 
##############################################################################
23
 
 
24
 
"""
25
 
Spanish Fiscal Year Closing
26
 
"""
27
 
__author__ = "Borja López Soilán (Pexego)"
28
 
 
29
 
 
30
 
from osv import fields, osv
31
 
from tools.translate import _
32
 
from datetime import datetime
33
 
import netsvc
34
 
from tools import config
35
 
 
36
 
#-------------------------------------------------------------------------------
37
 
# Default Spanish Account Mappings
38
 
#-------------------------------------------------------------------------------
39
 
 
40
 
# Format for the mappings:
41
 
#       (<source account code>, <dest account code>, <description>)
42
 
 
43
 
# Loss & Profit
44
 
_LP_ACCOUNT_MAPPING = [
45
 
    ('6', '129%', False),
46
 
    ('7', '129%', False),
47
 
]
48
 
 
49
 
# Net Loss & Profit
50
 
_NLP_ACCOUNT_MAPPING = [
51
 
    ('800', '133%', False),
52
 
    ('802', '133%', False),
53
 
    ('810', '1340%0', False),
54
 
    ('811', '1341%0', False),
55
 
    ('812', '1340%0', False),
56
 
    ('813', '1341%0', False),
57
 
    ('820', '135%0', False),
58
 
    ('821', '135%0', False),
59
 
    ('830', '13', False), # Can be any 13? account, like 130 or 133
60
 
    ('833', '13', False), # Can be any 13? account, like 130 or 133
61
 
    ('834', '137%0', False),
62
 
    ('835', '137%0', False),
63
 
    ('835', '137%0', False),
64
 
    ('838', '133%0', False),
65
 
    ('840', '130%0', False),
66
 
    ('841', '131%0', False),
67
 
    ('842', '132%0', False),
68
 
    ('850', '115%0', False),
69
 
    ('851', '115%0', False),
70
 
    ('860', '136%0', False),
71
 
    ('862', '136%0', False),
72
 
    ('890', '133%0', False),
73
 
    ('892', '133%0', False),
74
 
    ('900', '133%', False),
75
 
    ('902', '133%', False),
76
 
    ('910', '1340%0', False),
77
 
    ('911', '1341%0', False),
78
 
    ('912', '1340%0', False),
79
 
    ('913', '1341%0', False),
80
 
    ('920', '135%0', False),
81
 
    ('921', '135%0', False),
82
 
    ('940', '130%0', False),
83
 
    ('941', '131%0', False),
84
 
    ('942', '132%0', False),
85
 
    ('950', '115%0', False),
86
 
    ('951', '115%0', False),
87
 
    ('960', '136%0', False),
88
 
    ('962', '136%0', False),
89
 
    ('990', '133%0', False),
90
 
    ('991', '133%0', False),
91
 
    ('992', '133%0', False),
92
 
    ('993', '133%0', False),
93
 
]
94
 
 
95
 
# Closing
96
 
_C_ACCOUNT_MAPPING = [
97
 
    ('1', False, False),
98
 
    ('2', False, False),
99
 
    ('3', False, False),
100
 
    ('4', False, False),
101
 
    ('5', False, False),
102
 
]
103
 
 
104
 
 
105
 
 
106
 
#-------------------------------------------------------------------------------
107
 
# Predeclaration of the FYC object
108
 
#-------------------------------------------------------------------------------
109
 
class fiscal_year_closing_init(osv.osv):
110
 
    """
111
 
    Spanish Fiscal Year Closing Wizard
112
 
    """
113
 
 
114
 
    _name = "l10n_es_cierre_ejercicio.fyc"
115
 
    _description = "Spanish Fiscal Year Closing Wizard"
116
 
 
117
 
    _columns = {
118
 
        'name': fields.char('Description', size=60, required=True),
119
 
    }
120
 
 
121
 
fiscal_year_closing_init()
122
 
 
123
 
 
124
 
#-------------------------------------------------------------------------------
125
 
# Account mapping objects (to be used on the fyc configuration)
126
 
#-------------------------------------------------------------------------------
127
 
 
128
 
class fiscal_year_closing_lp_account_mapping(osv.osv):
129
 
    """
130
 
    Loss & Profit Account Mapping
131
 
    """
132
 
 
133
 
    _name = "l10n_es_cierre_ejercicio.fyc_lp_account_map"
134
 
    _description = "SFYC Loss & Profit Account Mapping"
135
 
 
136
 
    _columns = {
137
 
        'name': fields.char('Description', size=60, required=False),
138
 
 
139
 
        # Parent eoy
140
 
        'fyc_id': fields.many2one('l10n_es_cierre_ejercicio.fyc', 'Fiscal Year Closing', ondelete='cascade', required=True, select=1),
141
 
 
142
 
        # Accounts
143
 
        'source_account_id':fields.many2one('account.account', 'Source account', required=True, ondelete='cascade'),
144
 
        'dest_account_id':fields.many2one('account.account', 'Dest account', required=False, ondelete='cascade'),
145
 
    }
146
 
fiscal_year_closing_lp_account_mapping()
147
 
 
148
 
 
149
 
class fiscal_year_closing_nlp_account_mapping(osv.osv):
150
 
    """
151
 
    Net Loss & Profit Account Mapping
152
 
    """
153
 
 
154
 
    _name = "l10n_es_cierre_ejercicio.fyc_nlp_account_map"
155
 
    _description = "SFYC Net Loss & Profit Account Mapping"
156
 
 
157
 
    _columns = {
158
 
        'name': fields.char('Description', size=60, required=False),
159
 
 
160
 
        # Parent eoy
161
 
        'fyc_id': fields.many2one('l10n_es_cierre_ejercicio.fyc', 'Fiscal Year Closing', ondelete='cascade', required=True, select=1),
162
 
 
163
 
        # Accounts
164
 
        'source_account_id':fields.many2one('account.account', 'Source account', required=True, ondelete='cascade'),
165
 
        'dest_account_id':fields.many2one('account.account', 'Dest account', required=False, ondelete='cascade'),
166
 
    }
167
 
fiscal_year_closing_nlp_account_mapping()
168
 
 
169
 
 
170
 
class fiscal_year_closing_c_account_mapping(osv.osv):
171
 
    """
172
 
    Closing Account Mapping
173
 
    """
174
 
 
175
 
    _name = "l10n_es_cierre_ejercicio.fyc_c_account_map"
176
 
    _description = "SFYC Closing Account Mapping"
177
 
 
178
 
    _columns = {
179
 
        'name': fields.char('Description', size=60, required=False),
180
 
 
181
 
        # Parent eoy
182
 
        'fyc_id': fields.many2one('l10n_es_cierre_ejercicio.fyc', 'Fiscal Year Closing', ondelete='cascade', required=True, select=1),
183
 
 
184
 
        # Accounts
185
 
        'source_account_id':fields.many2one('account.account', 'Account', required=True, ondelete='cascade'),
186
 
        'dest_account_id':fields.many2one('account.account', 'Dest account', ondelete='cascade'),
187
 
    }
188
 
fiscal_year_closing_c_account_mapping()
189
 
 
190
 
#-------------------------------------------------------------------------------
191
 
# Spanish Fiscal Year Closing Wizard
192
 
#-------------------------------------------------------------------------------
193
 
class fiscal_year_closing(osv.osv):
194
 
    """
195
 
    Spanish Fiscal Year Closing Wizard
196
 
    """
197
 
 
198
 
    _inherit = "l10n_es_cierre_ejercicio.fyc"
199
 
 
200
 
    #
201
 
    # Fields -------------------------------------------------------------------
202
 
    #
203
 
 
204
 
    _columns = {
205
 
        # Company
206
 
        'company_id': fields.many2one('res.company', 'Company', ondelete='cascade', readonly=True, required=True),
207
 
 
208
 
        # Fiscal years
209
 
        'closing_fiscalyear_id':fields.many2one('account.fiscalyear', 'Fiscal year to close', required=True, ondelete='cascade', select=1),
210
 
        'opening_fiscalyear_id':fields.many2one('account.fiscalyear', 'Fiscal year to open', required=True, ondelete='cascade', select=2),
211
 
 
212
 
        #
213
 
        # Operations (to do), and their account moves (when done)
214
 
        #
215
 
        'create_loss_and_profit': fields.boolean('Create Loss & Profit move'),
216
 
        'loss_and_profit_move_id': fields.many2one('account.move', 'L&P Move', ondelete='set null', readonly=True),
217
 
        'create_net_loss_and_profit': fields.boolean('Create Net Loss & Profit'),
218
 
        'net_loss_and_profit_move_id': fields.many2one('account.move', 'Net L&P Move', ondelete='set null', readonly=True),
219
 
        'create_closing': fields.boolean('Close fiscal year'),
220
 
        'closing_move_id': fields.many2one('account.move', 'Closing Move', ondelete='set null', readonly=True),
221
 
        'create_opening': fields.boolean('Open next fiscal year'),
222
 
        'opening_move_id': fields.many2one('account.move', 'Opening Move', ondelete='set null', readonly=True),
223
 
 
224
 
        #
225
 
        # Extra operations
226
 
        #
227
 
        'check_invalid_period_moves': fields.boolean('Check invalid period or date moves', help="Checks that there are no moves, on the fiscal year that is being closed, with dates or periods outside that fiscal year."),
228
 
        'check_draft_moves': fields.boolean('Check draft moves', help="Checks that there are no draft moves on the fiscal year that is being closed. Non-confirmed moves won't be taken in account on the closing operations."),
229
 
        'check_unbalanced_moves': fields.boolean('Check unbalanced moves', help="Checks that there are no unbalanced moves on the fiscal year that is being closed."),
230
 
 
231
 
        # State
232
 
        'state': fields.selection([
233
 
                ('new', 'New'),
234
 
                ('draft', 'Draft'),
235
 
                ('in_progress', 'In Progress'),
236
 
                ('done', 'Done'),
237
 
                ('canceled', 'Canceled'),
238
 
            ], 'Status'),
239
 
 
240
 
        #
241
 
        # Loss and Profit options
242
 
        #
243
 
        'lp_description': fields.char('Description', size=60),
244
 
        'lp_journal_id': fields.many2one('account.journal', 'Journal'),
245
 
        'lp_period_id': fields.many2one('account.period', 'Period'),
246
 
        'lp_date': fields.date('Date'),
247
 
        'lp_account_mapping_ids': fields.one2many('l10n_es_cierre_ejercicio.fyc_lp_account_map', 'fyc_id', 'Account mappings'),
248
 
 
249
 
        #
250
 
        # Net Loss and Profit options
251
 
        #
252
 
        'nlp_description': fields.char('Description', size=60),
253
 
        'nlp_journal_id': fields.many2one('account.journal', 'Journal'),
254
 
        'nlp_period_id': fields.many2one('account.period', 'Period'),
255
 
        'nlp_date': fields.date('Date'),
256
 
        'nlp_account_mapping_ids': fields.one2many('l10n_es_cierre_ejercicio.fyc_nlp_account_map', 'fyc_id', 'Account mappings'),
257
 
 
258
 
        #
259
 
        # Closing options
260
 
        #
261
 
        'c_description': fields.char('Description', size=60),
262
 
        'c_journal_id': fields.many2one('account.journal', 'Journal'),
263
 
        'c_period_id': fields.many2one('account.period', 'Period'),
264
 
        'c_date': fields.date('Date'),
265
 
        'c_account_mapping_ids': fields.one2many('l10n_es_cierre_ejercicio.fyc_c_account_map', 'fyc_id', 'Accounts'),
266
 
 
267
 
        #
268
 
        # Opening options
269
 
        #
270
 
        'o_description': fields.char('Description', size=60),
271
 
        'o_journal_id': fields.many2one('account.journal', 'Journal'),
272
 
        'o_period_id': fields.many2one('account.period', 'Period'),
273
 
        'o_date': fields.date('Date'),
274
 
    }
275
 
 
276
 
    #
277
 
    # Default values -----------------------------------------------------------
278
 
    #
279
 
 
280
 
    def _get_closing_fiscalyear_id(self, cr, uid, context):
281
 
        """
282
 
        Gets the last (previous) fiscal year
283
 
        """
284
 
        company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
285
 
        str_date = '%s-06-01' % (datetime.now().year - 1)
286
 
        fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [
287
 
                            ('company_id', '=', company.id),
288
 
                            ('date_start', '<=', str_date),
289
 
                            ('date_stop', '>=', str_date),
290
 
                        ])
291
 
        if not fiscalyear_ids:
292
 
            fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [
293
 
                    ('company_id', '=', False),
294
 
                    ('date_start', '<=', str_date),
295
 
                    ('date_stop', '>=', str_date),
296
 
                ])
297
 
        return fiscalyear_ids and fiscalyear_ids[0]
298
 
 
299
 
    def _get_opening_fiscalyear_id(self, cr, uid, context):
300
 
        """
301
 
        Gets the current fiscal year
302
 
        """
303
 
        company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
304
 
        str_date = '%s-06-01' % datetime.now().year
305
 
        fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [
306
 
                            ('company_id', '=', company.id),
307
 
                            ('date_start', '<=', str_date),
308
 
                            ('date_stop', '>=', str_date),
309
 
                        ])
310
 
        if not fiscalyear_ids:
311
 
            fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [
312
 
                    ('company_id', '=', False),
313
 
                    ('date_start', '<=', str_date),
314
 
                    ('date_stop', '>=', str_date),
315
 
                ])
316
 
        return fiscalyear_ids and fiscalyear_ids[0]
317
 
    
318
 
    _defaults = {
319
 
        # Current company by default:
320
 
        'company_id': lambda self, cr, uid, context: self.pool.get('res.users').browse(cr, uid, uid, context).company_id.id,
321
 
 
322
 
        # Draft state by default:
323
 
        'state': lambda *a: 'new',
324
 
 
325
 
        # Name
326
 
        'name': lambda self, cr, uid, context: _("%s Fiscal Year Closing") % (datetime.now().year - 1),
327
 
 
328
 
        # Fiscal years
329
 
        'closing_fiscalyear_id': _get_closing_fiscalyear_id,
330
 
        'opening_fiscalyear_id': _get_opening_fiscalyear_id,
331
 
    }
332
 
 
333
 
    #
334
 
    # Workflow actions ---------------------------------------------------------
335
 
    #
336
 
 
337
 
    def _get_journal_id(self, cr, uid, fyc, context):
338
 
        """
339
 
        Gets the journal to use.
340
 
        (It will search for a 'GRAL' or 'General' journal)
341
 
        """
342
 
        assert fyc.company_id, "A company should have been selected"
343
 
        journal_ids = self.pool.get('account.journal').search(cr, uid, [
344
 
                            ('company_id', '=', fyc.company_id.id),
345
 
                            ('code', '=', 'GRAL'),
346
 
                        ])
347
 
        if not journal_ids:
348
 
            journal_ids = self.pool.get('account.journal').search(cr, uid, [
349
 
                            ('company_id', '=', False),
350
 
                            ('code', '=', 'GRAL'),
351
 
                        ])
352
 
        if not journal_ids:
353
 
            journal_ids = self.pool.get('account.journal').search(cr, uid, [
354
 
                            ('company_id', '=', fyc.company_id.id),
355
 
                            ('name', 'ilike', 'General'),
356
 
                        ])
357
 
        if not journal_ids:
358
 
            journal_ids = self.pool.get('account.journal').search(cr, uid, [
359
 
                            ('company_id', '=', False),
360
 
                            ('name', 'ilike', 'General'),
361
 
                        ])
362
 
        return journal_ids and journal_ids[0]
363
 
 
364
 
    def _get_lp_period_id(self, cr, uid, fyc, context):
365
 
        """
366
 
        Gets the period for the L&P entry
367
 
        (It searches for a "PG%" special period on the previous fiscal year)
368
 
        """
369
 
        period_ids = self.pool.get('account.period').search(cr, uid, [
370
 
                            ('fiscalyear_id', '=', fyc.closing_fiscalyear_id.id),
371
 
                            ('special', '=', True),
372
 
                            ('date_start', '=', fyc.closing_fiscalyear_id.date_stop),
373
 
                            ('code', 'ilike', 'PG'),
374
 
                        ])
375
 
        return period_ids and period_ids[0]
376
 
 
377
 
    def _get_c_period_id(self, cr, uid, fyc, context):
378
 
        """
379
 
        Gets the period for the Closing entry
380
 
        (It searches for a "C%" special period on the previous fiscal year)
381
 
        """
382
 
        period_ids = self.pool.get('account.period').search(cr, uid, [
383
 
                            ('fiscalyear_id', '=', fyc.closing_fiscalyear_id.id),
384
 
                            ('special', '=', True),
385
 
                            ('date_start', '=', fyc.closing_fiscalyear_id.date_stop),
386
 
                            ('code', 'ilike', 'C'),
387
 
                        ])
388
 
        return period_ids and period_ids[0]
389
 
 
390
 
    def _get_o_period_id(self, cr, uid, fyc, context):
391
 
        """
392
 
        Gets the period for the Opening entry
393
 
        (It searches for a "A%" special period on the previous fiscal year)
394
 
        """
395
 
        period_ids = self.pool.get('account.period').search(cr, uid, [
396
 
                            ('fiscalyear_id', '=', fyc.opening_fiscalyear_id.id),
397
 
                            ('special', '=', True),
398
 
                            ('date_stop', '=', fyc.opening_fiscalyear_id.date_start),
399
 
                            ('code', 'ilike', 'A'),
400
 
                        ])
401
 
        return period_ids and period_ids[0]
402
 
 
403
 
 
404
 
    def _get_account_mappings(self, cr, uid, fyc, mapping, context):
405
 
        """
406
 
        Transforms the mapping dictionary on a list of mapping lines.
407
 
        """
408
 
        account_mappings = []
409
 
        for source, dest, description in mapping:
410
 
            #
411
 
            # Find the source account
412
 
            #
413
 
            account_ids = self.pool.get('account.account').search(cr, uid, [
414
 
                            ('company_id', '=', fyc.company_id.id),
415
 
                            ('code', '=like', source),
416
 
                        ])
417
 
            source_account_id = account_ids and account_ids[0] or None
418
 
 
419
 
            #
420
 
            # Find the dest account
421
 
            #
422
 
            account_ids = self.pool.get('account.account').search(cr, uid, [
423
 
                            ('company_id', '=', fyc.company_id.id),
424
 
                            ('code', '=like', dest),
425
 
                            ('type', '!=', 'view'),
426
 
                        ])
427
 
            dest_account_id = account_ids and account_ids[0] or None
428
 
 
429
 
            #
430
 
            # Use a default description if not provided
431
 
            #
432
 
            if not description:
433
 
                if source_account_id:
434
 
                    description = self.pool.get('account.account').read(cr, uid, source_account_id, ['name'])['name']
435
 
 
436
 
            #
437
 
            # If the mapping is valid for this chart of accounts
438
 
            #
439
 
            if source_account_id:
440
 
                #
441
 
                # Make sure that the dest account is valid
442
 
                #
443
 
                if dest_account_id:
444
 
                    # Add the line to the result
445
 
                    account_mappings.append({
446
 
                            'name': description,
447
 
                            'source_account_id': source_account_id,
448
 
                            'dest_account_id': dest_account_id,
449
 
                        })
450
 
                else:
451
 
                    # Add the line to the result
452
 
                    account_mappings.append({
453
 
                            'name': _('No destination account %s found for account %s.') % (dest, source),
454
 
                            'source_account_id': source_account_id,
455
 
                            'dest_account_id': None,
456
 
                        })
457
 
 
458
 
        return [(0, 0, acc_map) for acc_map in account_mappings]
459
 
 
460
 
 
461
 
 
462
 
    def action_draft(self, cr, uid, ids, context=None):
463
 
        """
464
 
        Called when the user clicks the confirm button.
465
 
        """
466
 
        if context is None:
467
 
            context = {}
468
 
        #
469
 
        # Make sure the lang is defined on the context
470
 
        #
471
 
        user = self.pool.get('res.users').browse(cr, uid, uid, context)
472
 
        context['lang'] = context.get('lang') or user.context_lang
473
 
 
474
 
        for fyc in self.browse(cr, uid, ids, context):
475
 
            #
476
 
            # Check for duplicated entries
477
 
            #
478
 
            fyc_ids = self.search(cr, uid, [('name', '=', fyc.name)])
479
 
            if len(fyc_ids) > 1:
480
 
                raise osv.except_osv(_('Error'), _('There is already a fiscal year closing with this name.'))
481
 
            
482
 
            assert fyc.closing_fiscalyear_id and fyc.closing_fiscalyear_id.id
483
 
            fyc_ids = self.search(cr, uid, [('closing_fiscalyear_id', '=', fyc.closing_fiscalyear_id.id)])
484
 
            if len(fyc_ids) > 1:
485
 
                raise osv.except_osv(_('Error'), _('There is already a fiscal year closing for the fiscal year to close.'))
486
 
 
487
 
            assert fyc.opening_fiscalyear_id and fyc.opening_fiscalyear_id.id
488
 
            fyc_ids = self.search(cr, uid, [('opening_fiscalyear_id', '=', fyc.opening_fiscalyear_id.id)])
489
 
            if len(fyc_ids) > 1:
490
 
                raise osv.except_osv(_('Error'), _('There is already a fiscal year closing for the fiscal year to open.'))
491
 
 
492
 
            #
493
 
            # Check whether the default values of the fyc object have to be computed
494
 
            # or they have already been computed (restarted workflow)
495
 
            #
496
 
            if fyc.c_account_mapping_ids:
497
 
                # Fyc wizard reverted to 'new' after canceled
498
 
 
499
 
                self.write(cr, uid, [fyc.id], { 'state': 'draft' })
500
 
            else:
501
 
                # New fyc wizard object
502
 
 
503
 
                vals = {
504
 
                    #
505
 
                    # Perform all the operations by default
506
 
                    #
507
 
                    'create_loss_and_profit': True,
508
 
                    'create_net_loss_and_profit': True,
509
 
                    'create_closing': True,
510
 
                    'create_opening': True,
511
 
 
512
 
                    'check_invalid_period_moves': True,
513
 
                    'check_draft_moves': True,
514
 
                    'check_unbalanced_moves': True,
515
 
 
516
 
                    #
517
 
                    # L&P options
518
 
                    #
519
 
                    'lp_description': _("Loss & Profit"),
520
 
                    'lp_journal_id': self._get_journal_id(cr, uid, fyc, context),
521
 
                    'lp_period_id': self._get_lp_period_id(cr, uid, fyc, context),
522
 
                    'lp_date': fyc.closing_fiscalyear_id.date_stop,
523
 
                    'lp_account_mapping_ids': self._get_account_mappings(cr, uid, fyc, _LP_ACCOUNT_MAPPING, context),
524
 
 
525
 
                    #
526
 
                    # Net L&P options
527
 
                    #
528
 
                    'nlp_description': _("Net Loss & Profit"),
529
 
                    'nlp_journal_id': self._get_journal_id(cr, uid, fyc, context),
530
 
                    'nlp_period_id': self._get_lp_period_id(cr, uid, fyc, context),
531
 
                    'nlp_date': fyc.closing_fiscalyear_id.date_stop,
532
 
                    'nlp_account_mapping_ids': self._get_account_mappings(cr, uid, fyc, _NLP_ACCOUNT_MAPPING, context),
533
 
 
534
 
                    #
535
 
                    # Closing options
536
 
                    #
537
 
                    'c_description': _("Fiscal Year Closing"),
538
 
                    'c_journal_id': self._get_journal_id(cr, uid, fyc, context),
539
 
                    'c_period_id': self._get_c_period_id(cr, uid, fyc, context),
540
 
                    'c_date': fyc.closing_fiscalyear_id.date_stop,
541
 
                    'c_account_mapping_ids': self._get_account_mappings(cr, uid, fyc, _C_ACCOUNT_MAPPING, context),
542
 
 
543
 
                    #
544
 
                    # Opening options
545
 
                    #
546
 
                    'o_description': _("Fiscal Year Opening"),
547
 
                    'o_journal_id': self._get_journal_id(cr, uid, fyc, context),
548
 
                    'o_period_id': self._get_o_period_id(cr, uid, fyc, context),
549
 
                    'o_date': fyc.opening_fiscalyear_id.date_start,
550
 
 
551
 
                    # *** New state ***
552
 
                    'state': 'draft',
553
 
                }
554
 
                self.write(cr, uid, [fyc.id], vals)
555
 
        return True
556
 
 
557
 
 
558
 
    def action_run(self, cr, uid, ids, context=None):
559
 
        """
560
 
        Called when the create entries button is used.
561
 
        """
562
 
        # Note: Just change the state, everything else is done on the run wizard
563
 
        #       *before* this action is called.
564
 
        self.write(cr, uid, ids, {'state': 'in_progress'})
565
 
        return True
566
 
 
567
 
 
568
 
    def action_confirm(self, cr, uid, ids, context=None):
569
 
        """
570
 
        Called when the user clicks the confirm button.
571
 
        """
572
 
        if context is None:
573
 
            context = {}
574
 
        #
575
 
        # Make sure the lang is defined on the context
576
 
        #
577
 
        user = self.pool.get('res.users').browse(cr, uid, uid, context)
578
 
        context['lang'] = context.get('lang') or user.context_lang
579
 
 
580
 
        for fyc in self.browse(cr, uid, ids, context):
581
 
            #
582
 
            # Require the L&P, closing, and opening moves to exist (NL&P is optional)
583
 
            #
584
 
            if not fyc.loss_and_profit_move_id:
585
 
                raise osv.except_osv(_("Not all the operations have been performed!"), _("The Loss & Profit move is required"))
586
 
            if not fyc.closing_move_id:
587
 
                raise osv.except_osv(_("Not all the operations have been performed!"), _("The Closing move is required"))
588
 
            if not fyc.opening_move_id:
589
 
                raise osv.except_osv(_("Not all the operations have been performed!"), _("The Opening move is required"))
590
 
 
591
 
            #
592
 
            # Calculate the moves to check
593
 
            #
594
 
            moves = []
595
 
            moves.append(fyc.loss_and_profit_move_id)
596
 
            if fyc.net_loss_and_profit_move_id:
597
 
                moves.append(fyc.net_loss_and_profit_move_id)
598
 
            moves.append(fyc.closing_move_id)
599
 
            moves.append(fyc.opening_move_id)
600
 
 
601
 
            #
602
 
            # Check and reconcile each of the moves
603
 
            #
604
 
            for move in moves:
605
 
                netsvc.Logger().notifyChannel('fyc', netsvc.LOG_DEBUG, "Checking %s" % move.ref)
606
 
                #
607
 
                # Check if it has been confirmed
608
 
                #
609
 
                if move.state == 'draft':
610
 
                    raise osv.except_osv(_("Some moves are in draft state!"), _("You have to review and confirm each of the moves before continuing"))
611
 
                #
612
 
                # Check the balance
613
 
                #
614
 
                amount = 0
615
 
                for line in move.line_id:
616
 
                    amount += (line.debit - line.credit)
617
 
                if abs(amount) > 0.5 * 10 ** -int(config['price_accuracy']):
618
 
                    raise osv.except_osv(_("Some moves are unbalanced!"), _("All the moves should be balanced before continuing"))
619
 
 
620
 
                #
621
 
                # Reconcile the move
622
 
                #
623
 
                # Note: We will reconcile all the lines, even the 'not reconcile' ones,
624
 
                #       to prevent future problems (the user may change the
625
 
                #       reconcile option of an account in the future)
626
 
                #
627
 
                netsvc.Logger().notifyChannel('fyc', netsvc.LOG_DEBUG, "Reconcile %s" % move.ref)
628
 
                tmp_context = context.copy()
629
 
                tmp_context['fy_closing'] = True # Fiscal year closing = reconcile everything
630
 
                line_ids = [line.id for line in move.line_id]
631
 
                self.pool.get('account.move.line').reconcile(cr, uid, line_ids, context=tmp_context)
632
 
 
633
 
            #
634
 
            # Close the fiscal year and it's periods
635
 
            #
636
 
            # Note: We can not just do a write, cause it would raise a
637
 
            #       "You can not modify/delete a journal with entries for this period!"
638
 
            #       so we have to do it on SQL level :(
639
 
            #       This is based on the "account.fiscalyear.close.state" wizard.
640
 
            #
641
 
            netsvc.Logger().notifyChannel('fyc', netsvc.LOG_DEBUG, "Closing fiscal year")
642
 
            query = """
643
 
                    UPDATE account_journal_period
644
 
                    SET state = 'done'
645
 
                    WHERE period_id IN (SELECT id FROM account_period WHERE fiscalyear_id = %d)
646
 
                    """
647
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
648
 
            query = """
649
 
                    UPDATE account_period
650
 
                    SET state = 'done'
651
 
                    WHERE fiscalyear_id = %d
652
 
                    """
653
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
654
 
            query = """
655
 
                    UPDATE account_fiscalyear
656
 
                    SET state = 'done'
657
 
                    WHERE id = %d
658
 
                    """
659
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
660
 
 
661
 
        # Done
662
 
        self.write(cr, uid, ids, {'state': 'done'})
663
 
        return True
664
 
 
665
 
 
666
 
    def action_cancel(self, cr, uid, ids, context=None):
667
 
        """
668
 
        Called when the user clicks the cancel button.
669
 
        """
670
 
        if context is None:
671
 
            context = {}
672
 
        #
673
 
        # Make sure the lang is defined on the context
674
 
        #
675
 
        user = self.pool.get('res.users').browse(cr, uid, uid, context)
676
 
        context['lang'] = context.get('lang') or user.context_lang
677
 
 
678
 
        #
679
 
        # Uncheck all the operations
680
 
        #
681
 
        self.pool.get('l10n_es_cierre_ejercicio.fyc').write(cr, uid, ids, {
682
 
                    'create_loss_and_profit': False,
683
 
                    'create_net_loss_and_profit': False,
684
 
                    'create_closing': False,
685
 
                    'create_opening': False,
686
 
                    'check_invalid_period_moves': False,
687
 
                    'check_draft_moves': False,
688
 
                    'check_unbalanced_moves': False,
689
 
                }, context=context)
690
 
 
691
 
        #
692
 
        # Open the fiscal year and it's periods
693
 
        #
694
 
        # Note: We can not just do a write, cause it would raise a
695
 
        #       "You can not modify/delete a journal with entries for this period!"
696
 
        #       so we have to do it on SQL level :(
697
 
        #       This is based on the "account.fiscalyear.close.state" wizard.
698
 
        #
699
 
        for fyc in self.browse(cr, uid, ids, context):
700
 
            query = """
701
 
                    UPDATE account_journal_period
702
 
                    SET state = 'draft'
703
 
                    WHERE period_id IN (SELECT id FROM account_period WHERE fiscalyear_id = %d)
704
 
                    """
705
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
706
 
            query = """
707
 
                    UPDATE account_period
708
 
                    SET state = 'draft'
709
 
                    WHERE fiscalyear_id = %d
710
 
                    """
711
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
712
 
            query = """
713
 
                    UPDATE account_fiscalyear
714
 
                    SET state = 'draft'
715
 
                    WHERE id = %d
716
 
                    """
717
 
            cr.execute(query % fyc.closing_fiscalyear_id.id)
718
 
 
719
 
 
720
 
        # Canceled
721
 
        self.write(cr, uid, ids, {'state': 'canceled'})
722
 
 
723
 
        # Note: Everything else (removing the account moves) is done on the
724
 
        #       cancel wizard *after* this action returns.
725
 
        return True
726
 
 
727
 
 
728
 
    def action_recover(self, cr, uid, ids, context=None):
729
 
        """
730
 
        Called when the user clicks the draft button to create
731
 
        a new workflow instance.
732
 
        """
733
 
        self.write(cr, uid, ids, {'state': 'new'})
734
 
        wf_service = netsvc.LocalService("workflow")
735
 
        for item_id in ids:
736
 
            wf_service.trg_create(uid, 'l10n_es_cierre_ejercicio.fyc', item_id, cr)
737
 
        return True
738
 
 
739
 
 
740
 
fiscal_year_closing()
741
 
 
742
 
 
743
 
 
744
 
 
745
 
 
746