1
# -*- encoding: utf-8 -*-
2
##############################################################################
4
# Account reversal module for OpenERP
5
# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved
6
# @author Alexis de Lattre <alexis.delattre@akretion.com>
7
# with the kind advice of Nicolas Bessi from Camptocamp
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU Affero General Public License as
11
# published by the Free Software Foundation, either version 3 of the
12
# License, or (at your option) any later version.
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 Affero General Public License for more details.
19
# You should have received a copy of the GNU Affero General Public License
20
# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
##############################################################################
24
from osv import fields, osv
25
from tools.translate import _
27
class account_move(osv.osv):
28
_inherit = "account.move"
30
def create_reversal(self, cr, uid, ids, reversal_date, reversal_ref_prefix=False, reversal_line_prefix=False, reconcile=True, context=None):
31
move_line_obj = self.pool.get('account.move.line')
32
reversed_move_ids = []
33
for src_move in self.browse(cr, uid, ids, context=context):
34
reversal_move_id = self.copy(cr, uid, src_move.id,
36
'date': reversal_date,
37
'period_id': self.pool.get('account.period').find(cr, uid, reversal_date, context=context)[0],
38
'ref': ''.join([x for x in [reversal_ref_prefix, src_move.ref] if x]),
40
reversed_move_ids.append(reversal_move_id)
41
reversal_move = self.browse(cr, uid, reversal_move_id, context=context)
42
for reversal_move_line in reversal_move.line_id:
43
move_line_obj.write(cr, uid, [reversal_move_line.id], {
44
'debit': reversal_move_line.credit,
45
'credit': reversal_move_line.debit,
46
'amount_currency': reversal_move_line.amount_currency * -1,
47
'name': ' '.join([x for x in [reversal_line_prefix, reversal_move_line.name] if x]),
48
}, context=context, check=True, update_check=True)
50
# re-generate analytic lines for moves with validate function
51
self.validate(cr, uid, [reversal_move_id], context=context)
53
for src_move_line in src_move.line_id:
54
if not src_move_line.account_id.reconcile and not src_move_line.reconcile_id:
57
for reversal_move_line in reversal_move.line_id:
58
# Given that we are in a wizard, the move_line_obj.write that we
59
# performed above will not be taken into account until the
60
# end of the wizard => debit and credit are still not swapped
61
# in the reversal move
62
if reversal_move_line.account_id == src_move_line.account_id and reversal_move_line.credit == src_move_line.credit and reversal_move_line.debit == src_move_line.debit and not reversal_move_line.reconcile_id:
63
move_line_obj.reconcile(cr, uid, [src_move_line.id, reversal_move_line.id], context=context)
64
return reversed_move_ids
69
class account_reversal_wizard(osv.osv_memory):
70
_name = "account.reversal.wizard"
71
_description = "Wizard to reverse an account move"
73
'reversal_date': fields.date('Date of reversals', required=True, help="Enter the date of the reversal account moves. By default, OpenERP proposes the first day of the next period."),
74
'reversal_ref_prefix': fields.char('Prefix for Ref of reversal moves', size=32, help="Prefix that will be added to the 'Ref' of the original account moves to create the 'Ref' of the reversal moves (no space added after the prefix)."),
75
'reversal_line_prefix': fields.char('Prefix for Name of reversal move lines', size=32, help="Prefix that will be added to the name of the original account move lines to create the name of the reversal move lines (a space is added after the prefix)."),
76
'reversal_reconcile': fields.boolean('Reconcile reversals', help="If active, the reversal account moves will be reconciled with the original account moves."),
80
def _first_day_next_period(self, cr, uid, context=None):
83
first_day_next_period = False
84
if context.get('active_ids', False):
85
period_src = self.pool.get('account.move').browse(cr, uid, context['active_ids'][0], context=context).period_id
86
period_reversal_id = self.pool.get('account.period').next(cr, uid, period_src, 1, context=context)
87
first_day_next_period = self.pool.get('account.period').read(cr, uid, period_reversal_id, ['date_start'], context=context)['date_start']
88
return first_day_next_period
91
'reversal_date': _first_day_next_period,
92
'reversal_line_prefix': lambda *a: 'REV -',
93
'reversal_reconcile': lambda *a: True,
97
def start_wizard_reversal(self, cr, uid, ids, context=None):
100
res = self.read(cr, uid, ids)[0]
101
# WARNING : if the user is in the tree view and doesn't select any line,
102
# context['active_ids'] contains all the lines of the tree view
103
if context.get('active_ids', False):
104
reversed_move_ids = self.pool.get('account.move').create_reversal(cr, uid, context['active_ids'], res['reversal_date'], res['reversal_ref_prefix'], res['reversal_line_prefix'], reconcile=res['reversal_reconcile'], context=context)
106
'name': 'Reversal account moves',
108
'view_mode': 'tree,form',
110
'res_model': 'account.move',
111
'type': 'ir.actions.act_window',
113
'res_id': reversed_move_ids,
118
account_reversal_wizard()