2010-04-09 11:09:59 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
2010-10-15 13:35:22 +00:00
2012-12-06 14:56:32 +00:00
from openerp . osv import fields , osv
from openerp . tools . translate import _
2010-04-09 11:09:59 +00:00
class account_fiscalyear_close ( osv . osv_memory ) :
"""
Closes Account Fiscalyear and Generate Opening entries for New Fiscalyear
"""
_name = " account.fiscalyear.close "
_description = " Fiscalyear Close "
_columns = {
' fy_id ' : fields . many2one ( ' account.fiscalyear ' , \
2010-10-14 09:11:55 +00:00
' Fiscal Year to close ' , required = True , help = " Select a Fiscal year to close " ) ,
2010-04-09 11:09:59 +00:00
' fy2_id ' : fields . many2one ( ' account.fiscalyear ' , \
' New Fiscal Year ' , required = True ) ,
2010-11-16 12:16:58 +00:00
' journal_id ' : fields . many2one ( ' account.journal ' , ' Opening Entries Journal ' , domain = " [( ' type ' , ' = ' , ' situation ' )] " , required = True , help = ' The best practice here is to use a journal dedicated to contain the opening entries of all fiscal years. Note that you should define it with default debit/credit accounts, of type \' situation \' and with a centralized counterpart. ' ) ,
' period_id ' : fields . many2one ( ' account.period ' , ' Opening Entries Period ' , required = True ) ,
2014-05-21 09:52:05 +00:00
' report_name ' : fields . char ( ' Name of new entries ' , required = True , help = " Give name of the new entries " ) ,
2010-08-19 11:51:57 +00:00
}
2010-04-09 11:09:59 +00:00
_defaults = {
2013-02-18 12:24:06 +00:00
' report_name ' : lambda self , cr , uid , context : _ ( ' End of Fiscal Year Entry ' ) ,
2010-08-19 11:51:57 +00:00
}
2010-04-09 11:09:59 +00:00
2010-04-09 11:48:13 +00:00
def data_save ( self , cr , uid , ids , context = None ) :
2010-04-09 11:09:59 +00:00
"""
This function close account fiscalyear and create entries in new fiscalyear
@param cr : the current row , from the database cursor ,
@param uid : the current user ’ s ID for security checks ,
@param ids : List of Account fiscalyear close state ’ s IDs
"""
2012-02-09 17:03:33 +00:00
def _reconcile_fy_closing ( cr , uid , ids , context = None ) :
"""
2012-08-06 15:44:10 +00:00
This private function manually do the reconciliation on the account_move_line given as ` ids ´ , and directly
2012-02-09 17:03:33 +00:00
through psql . It ' s necessary to do it this way because the usual `reconcile()´ function on account.move.line
2012-08-06 15:44:10 +00:00
object is really resource greedy ( not supposed to work on reconciliation between thousands of records ) and
2012-02-09 17:03:33 +00:00
it does a lot of different computation that are useless in this particular case .
"""
#check that the reconcilation concern journal entries from only one company
cr . execute ( ' select distinct(company_id) from account_move_line where id in %s ' , ( tuple ( ids ) , ) )
if len ( cr . fetchall ( ) ) > 1 :
2012-08-07 11:34:14 +00:00
raise osv . except_osv ( _ ( ' Warning! ' ) , _ ( ' The entries to reconcile should belong to the same company. ' ) )
2012-11-22 14:28:19 +00:00
r_id = self . pool . get ( ' account.move.reconcile ' ) . create ( cr , uid , { ' type ' : ' auto ' , ' opening_reconciliation ' : True } )
2012-02-09 17:03:33 +00:00
cr . execute ( ' update account_move_line set reconcile_id = %s where id in %s ' , ( r_id , tuple ( ids ) , ) )
2015-04-07 09:54:53 +00:00
# reconcile_ref deptends from reconcile_id but was not recomputed
obj_acc_move_line . _store_set_values ( cr , uid , ids , [ ' reconcile_ref ' ] , context = context )
2014-07-06 14:44:26 +00:00
obj_acc_move_line . invalidate_cache ( cr , uid , [ ' reconcile_id ' ] , ids , context = context )
2012-02-09 17:03:33 +00:00
return r_id
2010-04-09 11:09:59 +00:00
obj_acc_period = self . pool . get ( ' account.period ' )
obj_acc_fiscalyear = self . pool . get ( ' account.fiscalyear ' )
obj_acc_journal = self . pool . get ( ' account.journal ' )
2011-09-23 13:48:27 +00:00
obj_acc_move = self . pool . get ( ' account.move ' )
2010-04-09 11:09:59 +00:00
obj_acc_move_line = self . pool . get ( ' account.move.line ' )
obj_acc_account = self . pool . get ( ' account.account ' )
obj_acc_journal_period = self . pool . get ( ' account.journal.period ' )
2011-09-23 13:48:27 +00:00
currency_obj = self . pool . get ( ' res.currency ' )
2010-04-09 11:09:59 +00:00
2011-02-15 09:20:57 +00:00
data = self . browse ( cr , uid , ids , context = context )
2010-04-09 11:09:59 +00:00
2010-04-09 11:48:13 +00:00
if context is None :
context = { }
2011-02-15 09:20:57 +00:00
fy_id = data [ 0 ] . fy_id . id
2010-04-09 11:09:59 +00:00
2011-02-15 09:20:57 +00:00
cr . execute ( " SELECT id FROM account_period WHERE date_stop < (SELECT date_start FROM account_fiscalyear WHERE id = %s ) " , ( str ( data [ 0 ] . fy2_id . id ) , ) )
2010-06-23 13:33:32 +00:00
fy_period_set = ' , ' . join ( map ( lambda id : str ( id [ 0 ] ) , cr . fetchall ( ) ) )
2010-10-11 05:51:53 +00:00
cr . execute ( " SELECT id FROM account_period WHERE date_start > (SELECT date_stop FROM account_fiscalyear WHERE id = %s ) " , ( str ( fy_id ) , ) )
2010-06-23 13:33:32 +00:00
fy2_period_set = ' , ' . join ( map ( lambda id : str ( id [ 0 ] ) , cr . fetchall ( ) ) )
2010-04-09 11:09:59 +00:00
2011-10-12 12:35:00 +00:00
if not fy_period_set or not fy2_period_set :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' User Error! ' ) , _ ( ' The periods to generate opening entries cannot be found. ' ) )
2011-10-12 12:35:00 +00:00
2011-02-15 09:20:57 +00:00
period = obj_acc_period . browse ( cr , uid , data [ 0 ] . period_id . id , context = context )
new_fyear = obj_acc_fiscalyear . browse ( cr , uid , data [ 0 ] . fy2_id . id , context = context )
old_fyear = obj_acc_fiscalyear . browse ( cr , uid , fy_id , context = context )
2010-04-09 11:09:59 +00:00
2011-02-15 09:20:57 +00:00
new_journal = data [ 0 ] . journal_id . id
2010-04-09 11:09:59 +00:00
new_journal = obj_acc_journal . browse ( cr , uid , new_journal , context = context )
2012-02-09 16:16:41 +00:00
company_id = new_journal . company_id . id
2010-04-09 11:09:59 +00:00
if not new_journal . default_credit_account_id or not new_journal . default_debit_account_id :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' User Error! ' ) ,
2012-07-25 07:33:57 +00:00
_ ( ' The journal must have default credit and debit account. ' ) )
2010-10-20 13:43:32 +00:00
if ( not new_journal . centralisation ) or new_journal . entry_posted :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' User Error! ' ) ,
2012-08-06 15:44:10 +00:00
_ ( ' The journal must have centralized counterpart without the Skipping draft state option checked. ' ) )
2010-04-09 11:09:59 +00:00
2011-09-23 13:48:27 +00:00
#delete existing move and move lines if any
move_ids = obj_acc_move . search ( cr , uid , [
( ' journal_id ' , ' = ' , new_journal . id ) , ( ' period_id ' , ' = ' , period . id ) ] )
2010-04-09 11:09:59 +00:00
if move_ids :
2011-09-23 13:48:27 +00:00
move_line_ids = obj_acc_move_line . search ( cr , uid , [ ( ' move_id ' , ' in ' , move_ids ) ] )
2012-11-22 14:28:19 +00:00
obj_acc_move_line . _remove_move_reconcile ( cr , uid , move_line_ids , opening_reconciliation = True , context = context )
2011-09-23 13:48:27 +00:00
obj_acc_move_line . unlink ( cr , uid , move_line_ids , context = context )
obj_acc_move . unlink ( cr , uid , move_ids , context = context )
2010-09-07 04:28:31 +00:00
2010-06-23 13:33:32 +00:00
cr . execute ( " SELECT id FROM account_fiscalyear WHERE date_stop < %s " , ( str ( new_fyear . date_start ) , ) )
2010-04-09 11:09:59 +00:00
result = cr . dictfetchall ( )
2015-05-21 14:02:58 +00:00
fy_ids = [ x [ ' id ' ] for x in result ]
2010-04-09 11:09:59 +00:00
query_line = obj_acc_move_line . _query_get ( cr , uid ,
obj = ' account_move_line ' , context = { ' fiscalyear ' : fy_ids } )
2011-09-23 13:48:27 +00:00
#create the opening move
vals = {
' name ' : ' / ' ,
' ref ' : ' ' ,
' period_id ' : period . id ,
2012-01-12 09:21:49 +00:00
' date ' : period . date_start ,
2011-09-23 13:48:27 +00:00
' journal_id ' : new_journal . id ,
}
move_id = obj_acc_move . create ( cr , uid , vals , context = context )
#1. report of the accounts with defferal method == 'unreconciled'
cr . execute ( '''
2011-10-12 12:35:00 +00:00
SELECT a . id
2011-09-23 13:48:27 +00:00
FROM account_account a
LEFT JOIN account_account_type t ON ( a . user_type = t . id )
2011-10-12 12:35:00 +00:00
WHERE a . active
2014-07-10 05:53:51 +00:00
AND a . type not in ( ' view ' , ' consolidation ' )
2012-02-09 16:16:41 +00:00
AND a . company_id = % s
AND t . close_method = % s ''' , (company_id, ' unreconciled ' , ))
2011-09-23 13:48:27 +00:00
account_ids = map ( lambda x : x [ 0 ] , cr . fetchall ( ) )
if account_ids :
cr . execute ( '''
INSERT INTO account_move_line (
name , create_uid , create_date , write_uid , write_date ,
statement_id , journal_id , currency_id , date_maturity ,
partner_id , blocked , credit , state , debit ,
2011-10-12 12:35:00 +00:00
ref , account_id , period_id , date , move_id , amount_currency ,
quantity , product_id , company_id )
2011-09-23 13:48:27 +00:00
( SELECT name , create_uid , create_date , write_uid , write_date ,
statement_id , % s , currency_id , date_maturity , partner_id ,
blocked , credit , ' draft ' , debit , ref , account_id ,
2012-01-12 09:21:49 +00:00
% s , ( % s ) AS date , % s , amount_currency , quantity , product_id , company_id
2011-09-23 13:48:27 +00:00
FROM account_move_line
2011-10-12 12:35:00 +00:00
WHERE account_id IN % s
AND ''' + query_line + '''
2012-01-12 09:21:49 +00:00
AND reconcile_id IS NULL ) ''' , (new_journal.id, period.id, period.date_start, move_id, tuple(account_ids),))
2011-09-23 13:48:27 +00:00
#We have also to consider all move_lines that were reconciled
#on another fiscal year, and report them too
cr . execute ( '''
INSERT INTO account_move_line (
name , create_uid , create_date , write_uid , write_date ,
statement_id , journal_id , currency_id , date_maturity ,
partner_id , blocked , credit , state , debit ,
ref , account_id , period_id , date , move_id , amount_currency ,
quantity , product_id , company_id )
( SELECT
b . name , b . create_uid , b . create_date , b . write_uid , b . write_date ,
b . statement_id , % s , b . currency_id , b . date_maturity ,
b . partner_id , b . blocked , b . credit , ' draft ' , b . debit ,
2012-01-12 09:21:49 +00:00
b . ref , b . account_id , % s , ( % s ) AS date , % s , b . amount_currency ,
2011-09-23 13:48:27 +00:00
b . quantity , b . product_id , b . company_id
FROM account_move_line b
WHERE b . account_id IN % s
AND b . reconcile_id IS NOT NULL
AND b . period_id IN ( ''' +fy_period_set+ ''' )
AND b . reconcile_id IN ( SELECT DISTINCT ( reconcile_id )
FROM account_move_line a
2012-01-12 09:21:49 +00:00
WHERE a . period_id IN ( ''' +fy2_period_set+ ''' ) ) ) ''' , (new_journal.id, period.id, period.date_start, move_id, tuple(account_ids),))
2014-07-06 14:44:26 +00:00
self . invalidate_cache ( cr , uid , context = context )
2011-09-23 13:48:27 +00:00
#2. report of the accounts with defferal method == 'detail'
cr . execute ( '''
SELECT a . id
FROM account_account a
LEFT JOIN account_account_type t ON ( a . user_type = t . id )
WHERE a . active
2014-07-10 05:53:51 +00:00
AND a . type not in ( ' view ' , ' consolidation ' )
2012-02-09 16:16:41 +00:00
AND a . company_id = % s
AND t . close_method = % s ''' , (company_id, ' detail ' , ))
2011-09-23 13:48:27 +00:00
account_ids = map ( lambda x : x [ 0 ] , cr . fetchall ( ) )
if account_ids :
cr . execute ( '''
INSERT INTO account_move_line (
name , create_uid , create_date , write_uid , write_date ,
statement_id , journal_id , currency_id , date_maturity ,
partner_id , blocked , credit , state , debit ,
ref , account_id , period_id , date , move_id , amount_currency ,
quantity , product_id , company_id )
( SELECT name , create_uid , create_date , write_uid , write_date ,
statement_id , % s , currency_id , date_maturity , partner_id ,
blocked , credit , ' draft ' , debit , ref , account_id ,
2012-01-12 09:21:49 +00:00
% s , ( % s ) AS date , % s , amount_currency , quantity , product_id , company_id
2011-09-23 13:48:27 +00:00
FROM account_move_line
WHERE account_id IN % s
AND ''' + query_line + ''' )
2012-01-12 09:21:49 +00:00
''' , (new_journal.id, period.id, period.date_start, move_id, tuple(account_ids),))
2014-07-06 14:44:26 +00:00
self . invalidate_cache ( cr , uid , context = context )
2011-09-23 13:48:27 +00:00
#3. report of the accounts with defferal method == 'balance'
cr . execute ( '''
SELECT a . id
FROM account_account a
LEFT JOIN account_account_type t ON ( a . user_type = t . id )
WHERE a . active
2014-07-10 05:53:51 +00:00
AND a . type not in ( ' view ' , ' consolidation ' )
2012-02-09 16:16:41 +00:00
AND a . company_id = % s
AND t . close_method = % s ''' , (company_id, ' balance ' , ))
2011-09-23 13:48:27 +00:00
account_ids = map ( lambda x : x [ 0 ] , cr . fetchall ( ) )
query_1st_part = """
INSERT INTO account_move_line (
debit , credit , name , date , move_id , journal_id , period_id ,
2011-10-12 12:35:00 +00:00
account_id , currency_id , amount_currency , company_id , state ) VALUES
2011-09-23 13:48:27 +00:00
"""
query_2nd_part = " "
query_2nd_part_args = [ ]
for account in obj_acc_account . browse ( cr , uid , account_ids , context = { ' fiscalyear ' : fy_id } ) :
company_currency_id = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid ) . company_id . currency_id
if not currency_obj . is_zero ( cr , uid , company_currency_id , abs ( account . balance ) ) :
if query_2nd_part :
query_2nd_part + = ' , '
query_2nd_part + = " ( %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s ) "
query_2nd_part_args + = ( account . balance > 0 and account . balance or 0.0 ,
account . balance < 0 and - account . balance or 0.0 ,
data [ 0 ] . report_name ,
period . date_start ,
move_id ,
new_journal . id ,
period . id ,
account . id ,
account . currency_id and account . currency_id . id or None ,
2013-12-03 14:48:43 +00:00
account . foreign_balance if account . currency_id else 0.0 ,
2011-09-23 13:48:27 +00:00
account . company_id . id ,
' draft ' )
if query_2nd_part :
cr . execute ( query_1st_part + query_2nd_part , tuple ( query_2nd_part_args ) )
2014-07-06 14:44:26 +00:00
self . invalidate_cache ( cr , uid , context = context )
2011-09-23 13:48:27 +00:00
#validate and centralize the opening move
obj_acc_move . validate ( cr , uid , [ move_id ] , context = context )
#reconcile all the move.line of the opening move
ids = obj_acc_move_line . search ( cr , uid , [ ( ' journal_id ' , ' = ' , new_journal . id ) ,
2010-04-09 11:09:59 +00:00
( ' period_id.fiscalyear_id ' , ' = ' , new_fyear . id ) ] )
if ids :
2012-02-09 17:03:33 +00:00
reconcile_id = _reconcile_fy_closing ( cr , uid , ids , context = context )
2011-09-23 13:48:27 +00:00
#set the creation date of the reconcilation at the first day of the new fiscalyear, in order to have good figures in the aged trial balance
self . pool . get ( ' account.move.reconcile ' ) . write ( cr , uid , [ reconcile_id ] , { ' create_date ' : new_fyear . date_start } , context = context )
#create the journal.period object and link it to the old fiscalyear
2011-02-15 09:20:57 +00:00
new_period = data [ 0 ] . period_id . id
2011-09-23 13:48:27 +00:00
ids = obj_acc_journal_period . search ( cr , uid , [ ( ' journal_id ' , ' = ' , new_journal . id ) , ( ' period_id ' , ' = ' , new_period ) ] )
2010-04-09 11:09:59 +00:00
if not ids :
ids = [ obj_acc_journal_period . create ( cr , uid , {
2011-09-23 13:48:27 +00:00
' name ' : ( new_journal . name or ' ' ) + ' : ' + ( period . code or ' ' ) ,
2010-04-09 11:09:59 +00:00
' journal_id ' : new_journal . id ,
' period_id ' : period . id
} ) ]
cr . execute ( ' UPDATE account_fiscalyear ' \
' SET end_journal_period_id = %s ' \
' WHERE id = %s ' , ( ids [ 0 ] , old_fyear . id ) )
2014-07-06 14:44:26 +00:00
obj_acc_fiscalyear . invalidate_cache ( cr , uid , [ ' end_journal_period_id ' ] , [ old_fyear . id ] , context = context )
2011-09-23 13:48:27 +00:00
2010-12-28 10:44:45 +00:00
return { ' type ' : ' ir.actions.act_window_close ' }
2010-04-09 11:09:59 +00:00
2010-11-16 12:16:58 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: