diff --git a/account_reversal/README.rst b/account_reversal/README.rst index 1e04dad32..d7608337a 100644 --- a/account_reversal/README.rst +++ b/account_reversal/README.rst @@ -1,3 +1,7 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + Account Reversal ================ @@ -5,19 +9,68 @@ This module adds an action "Reversal" on account moves, to allow the accountant to create reversal account moves in 2 clicks. Also add on account entries: - * a checkbox and filter "to be reversed" - * a link between an entry and its reversal entry +* a checkbox and filter "to be reversed" +* a link between an entry and its reversal entry -Module originally developped by Alexis de Lattre -during the Akretion-Camptocamp code sprint of June 2011. +Odoo v9c include a similar action (overwritten by this addon), but with less +features, for instance: + +* Allowing inheritance +* Options like prefix (for journal entry and journal item), post and reconcile. +* Create a link between the entry and its reversal +* Mark entries to be reversed in the future. + +Usage +===== + +As in Odoo v9c, if you select an entry from Accounting > Adviser > Journal Entries, +then an action menu 'Reverse Entries' is available. If clicked, then a wizard +allows user to select Reversal Date, Reversal Journal, Prefix, Post and Reconcile. + +* If no Reversal Journal is selected, then the same journal is used +* If Post is True, then reversal entry will be posted else it will be leaved + as a draft entry +* If Post and Reconcile are True, then all entry lines with reconciled accounts + of the entry will be reconciled with the reserval entry ones. + +There is also a new menu Accounting > Adviser > Journal Entries to be Reversed +in order to allow tracking entries that must be reserved for any reason. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/92/9.0 + + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. Contributors -============ +------------ - * Alexis de Lattre (Akretion) - * Guewen Baconnier (Camptocamp) - * Nicolas Bessi (Camptocamp) - * Torvald Bringsvor (Bringsvor Consulting) - * Sandy Carter (Savoir-faire Linux) - * Stéphane Bidoul (ACSONE) +* Alexis de Lattre (Akretion) +* Guewen Baconnier (Camptocamp) +* Nicolas Bessi (Camptocamp) +* Torvald Bringsvor (Bringsvor Consulting) +* Sandy Carter (Savoir-faire Linux) +* Stéphane Bidoul (ACSONE) +* Antonio Espinosa (Tecnativa) +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_reversal/__init__.py b/account_reversal/__init__.py index 14167e578..2eb723313 100644 --- a/account_reversal/__init__.py +++ b/account_reversal/__init__.py @@ -1,24 +1,5 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Account reversal module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved -# @author Alexis de Lattre -# -# 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 . -# -############################################################################## +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import account_reversal +from . import models from . import wizard diff --git a/account_reversal/__openerp__.py b/account_reversal/__openerp__.py index 67b1f5a29..0f88586b6 100644 --- a/account_reversal/__openerp__.py +++ b/account_reversal/__openerp__.py @@ -1,40 +1,28 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Account reversal module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved -# @author Alexis de Lattre -# Copyright 2012-2013 Camptocamp SA -# @author Guewen Baconnier (Camptocamp) -# -# 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 . -# -############################################################################## - +# Copyright 2011 Alexis de Lattre +# Copyright 2012-2013 Guewen Baconnier (Camptocamp) +# Copyright 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Account Reversal', - 'version': '8.0.1.1.0', - 'category': 'Generic Modules/Accounting', - 'license': 'AGPL-3', - 'author': "Akretion,Camptocamp,Odoo Community Association (OCA)", - 'website': 'http://www.akretion.com/', - 'depends': ['account'], - 'data': [ - 'account_view.xml', - 'wizard/account_move_reverse_view.xml' - ], - 'installable': False, - 'active': False, + "name": "Account Reversal", + "summary": "Wizard for creating a reversal account move", + "version": "9.0.1.0.0", + "category": "Accounting & Finance", + "website": "https://odoo-community.org/", + "author": "Akretion," + "Camptocamp," + "ACSONE SA/NV," + "Tecnativa," + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "account" + ], + "data": [ + "wizard/account_move_reverse_view.xml", + "views/account_move_view.xml", + ], } diff --git a/account_reversal/account_reversal.py b/account_reversal/account_reversal.py deleted file mode 100644 index f9b10122a..000000000 --- a/account_reversal/account_reversal.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Account reversal module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved -# @author Alexis de Lattre -# with the kind advice of Nicolas Bessi from Camptocamp -# Copyright (C) 2012-2013 Camptocamp SA (http://www.camptocamp.com) -# @author Guewen Baconnier -# -# 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 . -# -############################################################################## - -from openerp import fields, models, api, _ - - -class account_move(models.Model): - _inherit = "account.move" - - to_be_reversed = fields.Boolean( - 'To Be Reversed', - help='Check this box if your entry has to be' - 'reversed at the end of period.') - reversal_id = fields.Many2one( - 'account.move', - 'Reversal Entry', - ondelete='set null', - readonly=True) - - @api.multi - def validate(self): - # TODO: remove this method if and when - # https://github.com/odoo/odoo/pull/7735 is merged - if self.env.context.get('novalidate'): - return - return super(account_move, self).validate() - - @api.multi - def _move_reversal(self, reversal_date, - reversal_period_id=False, reversal_journal_id=False, - move_prefix=False, move_line_prefix=False, - reconcile=False): - """ - Create the reversal of a move - - :param move: browse instance of the move to reverse - :param reversal_date: when the reversal must be input - :param reversal_period_id: facultative period to write on the move - (use the period of the date if empty - :param reversal_journal_id: facultative journal on which create - the move - :param move_prefix: prefix for the move's name - :param move_line_prefix: prefix for the move line's names - - :return: Returns the id of the created reversal move - """ - self.ensure_one() - period_obj = self.env['account.period'] - amlo = self.env['account.move.line'] - - if reversal_period_id: - reversal_period = period_obj.browse([reversal_period_id])[0] - else: - reversal_period = period_obj.with_context( - company_id=self.company_id.id, - account_period_prefer_normal=True).find(reversal_date)[0] - if not reversal_journal_id: - reversal_journal_id = self.journal_id.id - - if self.env['account.journal'].browse([ - reversal_journal_id]).company_id != self.company_id: - raise Warning(_('Wrong company Journal is %s but we have %s') % ( - reversal_journal_id.company_id.name, self.company_id.name)) - if reversal_period.company_id != self.company_id: - raise Warning(_('Wrong company Period is %s but we have %s') % ( - reversal_journal_id.company_id.name, self.company_id.name)) - - reversal_ref = ''.join([x for x in [move_prefix, self.ref] if x]) - reversal_move = self.copy(default={ - 'company_id': self.company_id.id, - 'date': reversal_date, - 'period_id': reversal_period.id, - 'ref': reversal_ref, - 'journal_id': reversal_journal_id, - 'to_be_reversed': False, - }) - - self.with_context(novalidate=True).write({ - 'reversal_id': reversal_move.id, - 'to_be_reversed': False, - }) - - rec_dict = {} - for rev_move_line in reversal_move.line_id: - rev_ml_name = ' '.join( - [x for x - in [move_line_prefix, rev_move_line.name] - if x] - ) - rev_move_line.write( - {'debit': rev_move_line.credit, - 'credit': rev_move_line.debit, - 'amount_currency': rev_move_line.amount_currency * -1, - 'name': rev_ml_name}, - check=True, - update_check=True) - - if reconcile and rev_move_line.account_id.reconcile: - rec_dict.setdefault( - (rev_move_line.account_id, rev_move_line.partner_id), - amlo.browse(False)) - rec_dict[(rev_move_line.account_id, rev_move_line.partner_id)]\ - += rev_move_line - - reversal_move.validate() - if reconcile: - for mline in self.line_id: - if mline.account_id.reconcile: - rec_dict[(mline.account_id, mline.partner_id)] += mline - - for to_rec_move_lines in rec_dict.itervalues(): - to_rec_move_lines.reconcile() - - return reversal_move.id - - @api.multi - def create_reversals(self, reversal_date, reversal_period_id=False, - reversal_journal_id=False, - move_prefix=False, move_line_prefix=False, - reconcile=False): - """ - Create the reversal of one or multiple moves - - :param reversal_date: when the reversal must be input - :param reversal_period_id: facultative period to write on the move - (use the period of the date if empty - :param reversal_journal_id: facultative journal on which create - the move - :param move_prefix: prefix for the move's name - :param move_line_prefix: prefix for the move line's names - - :return: Returns a list of ids of the created reversal moves - """ - return [ - move._move_reversal( - reversal_date, - reversal_period_id=reversal_period_id, - reversal_journal_id=reversal_journal_id, - move_prefix=move_prefix, - move_line_prefix=move_line_prefix, - reconcile=reconcile - ) - for move in self - if not move.reversal_id - ] diff --git a/account_reversal/account_view.xml b/account_reversal/account_view.xml deleted file mode 100644 index 6188325b4..000000000 --- a/account_reversal/account_view.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - account.move.reversal.tree - account.move - - - - - - - - - - account.move.reversal.form - account.move - - - - - - - - - - - account.move.reversal.select - account.move - - - - - - - - - - - - - - diff --git a/account_reversal/models/__init__.py b/account_reversal/models/__init__.py new file mode 100644 index 000000000..69fc58050 --- /dev/null +++ b/account_reversal/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import account_move diff --git a/account_reversal/models/account_move.py b/account_reversal/models/account_move.py new file mode 100644 index 000000000..70bf8fd58 --- /dev/null +++ b/account_reversal/models/account_move.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +# Copyright 2011 Alexis de Lattre +# Copyright 2011 Nicolas Bessi (Camptocamp) +# Copyright 2012-2013 Guewen Baconnier (Camptocamp) +# Copyright 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models, _ +from openerp.exceptions import UserError + + +class AccountMove(models.Model): + _inherit = "account.move" + + to_be_reversed = fields.Boolean( + string="To Be Reversed", + help="Check this box if your entry has to be reversed at the end " + "of period.") + reversal_id = fields.Many2one( + comodel_name='account.move', ondelete='set null', readonly=True, + string="Reversal Entry") + + def _move_lines_reverse_prepare(self, move, date=False, journal=False, + line_prefix=False): + for line in move.get('line_ids', []): + date = date or line[2].get('date', False) + journal_id = journal and journal.id + journal_id = journal_id or line[2].get('journal_id', False) + name = line[2].get('name', False) or line_prefix + debit = line[2].get('debit', 0.) + credit = line[2].get('credit', 0.) + amount_currency = line[2].get('amount_currency', 0.) + if line_prefix and line_prefix != name: + name = ' '.join([line_prefix, name]) + line[2].update({ + 'name': name, + 'date': date, + 'journal_id': journal_id, + 'debit': credit, + 'credit': debit, + 'amount_currency': -amount_currency, + }) + return move + + def _move_reverse_prepare(self, date=False, journal=False, + move_prefix=False): + self.ensure_one() + journal = journal or self.journal_id + if journal.company_id != self.company_id: + raise UserError( + _("Wrong company Journal is '%s' but we have '%s'") % ( + journal.company_id.name, self.company_id.name)) + ref = self.ref or move_prefix + if move_prefix and move_prefix != ref: + ref = ' '.join([move_prefix, ref]) + date = date or self.date + move = self.copy_data()[0] + move.update({ + 'journal_id': journal.id, + 'date': date, + 'ref': ref, + 'to_be_reversed': False, + 'state': 'draft', + }) + return move + + @api.multi + def move_reverse_reconcile(self): + for move in self.filtered('reversal_id'): + rec = {} + lines = move.reversal_id.line_ids.filtered('account_id.reconcile') + for line in lines: + rec.setdefault((line.account_id, line.partner_id), + self.env['account.move.line']) + rec[(line.account_id, line.partner_id)] += line + lines = move.line_ids.filtered('account_id.reconcile') + for line in lines: + rec[(line.account_id, line.partner_id)] += line + for lines in rec.itervalues(): + lines.reconcile() + return True + + @api.multi + def create_reversals(self, date=False, journal=False, move_prefix=False, + line_prefix=False, post=False, reconcile=False): + """ + Create the reversal of one or multiple moves + + :param self: moves to reverse + :param date: when the reversal must be input + (use original if empty) + :param journal: journal on which create the move + (use original if empty) + :param move_prefix: prefix for the move's name + :param line_prefix: prefix for the move line's names + :param reconcile: reconcile lines (if account with reconcile = True) + + :return: Returns a recordset of the created reversal moves + """ + moves = self.env['account.move'] + for orig in self: + data = orig._move_reverse_prepare( + date=date, journal=journal, move_prefix=move_prefix) + data = orig._move_lines_reverse_prepare( + data, date=date, journal=journal, line_prefix=line_prefix) + reversal_move = self.create(data) + moves |= reversal_move + orig.write({ + 'reversal_id': reversal_move.id, + 'to_be_reversed': False, + }) + if moves and post: + moves.post() + if reconcile: + moves.move_reverse_reconcile() + return moves diff --git a/account_reversal/tests/__init__.py b/account_reversal/tests/__init__.py index 9fc55ecce..2cbb6deab 100644 --- a/account_reversal/tests/__init__.py +++ b/account_reversal/tests/__init__.py @@ -1,23 +1,4 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# 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 . -# -############################################################################## +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_account_reversal diff --git a/account_reversal/tests/test_account_reversal.py b/account_reversal/tests/test_account_reversal.py index 96b08c114..8bd248846 100644 --- a/account_reversal/tests/test_account_reversal.py +++ b/account_reversal/tests/test_account_reversal.py @@ -1,120 +1,73 @@ -# -*- encoding: utf-8 -*- -# ############################################################################# -# -# Account partner required module for OpenERP -# Copyright (C) 2014 Acsone (http://acsone.eu). -# @author Stéphane Bidoul -# -# 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 . -# -############################################################################## +# -*- coding: utf-8 -*- +# Copyright 2014 Stéphane Bidoul +# Copyright 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import time -from datetime import datetime - -from openerp.tests import common -from openerp import fields +from openerp.tests.common import TransactionCase -class test_account_reversal(common.TransactionCase): +class TestAccountReversal(TransactionCase): def setUp(self): - super(test_account_reversal, self).setUp() + super(TestAccountReversal, self).setUp() self.move_obj = self.env['account.move'] self.move_line_obj = self.env['account.move.line'] - - def _create_move(self, with_partner, amount=100, period=None): - date = datetime.now() - company_id = self.env.ref('base.main_company').id - period = period or self.env.ref('account.period_0') - - journal = self.env['account.journal'].create({ + self.company_id = self.env.ref('base.main_company').id + self.partner = self.env['res.partner'].create({ + 'name': 'Test partner', + }) + self.journal = self.env['account.journal'].create({ 'name': 'Test journal', 'code': 'COD', 'type': 'sale', - 'sequence_id': self.env.ref('account.sequence_sale_journal').id, - 'company_id': company_id}) + 'company_id': self.company_id + }) + type_revenue = self.env.ref('account.data_account_type_revenue') + type_payable = self.env.ref('account.data_account_type_payable') + self.account_sale = self.env['account.account'].create({ + 'name': 'Test sale', + 'code': 'XX_700', + 'user_type_id': type_revenue.id, + }) + self.account_customer = self.env['account.account'].create({ + 'name': 'Test customer', + 'code': 'XX_430', + 'user_type_id': type_payable.id, + 'reconcile': True, + }) + def _create_move(self, with_partner=True, amount=100): move_vals = { - 'journal_id': journal.id, - 'period_id': period.id, - 'date': date, - 'company_id': company_id, - } - - # Why this doesn't work I don't know: - # acct = self.ref('account.a_sale' - account1, account2 = self.env['account.account'].search( - [('company_id', '=', company_id), ('type', '=', 'other')])[:2] - - move_id = self.move_obj.create(move_vals) - self.move_line_obj.create({ - 'move_id': move_id.id, - 'name': '/', - 'debit': 0, - 'credit': amount, - 'company_id': company_id, - 'account_id': account1.id}) - move_line_id = self.move_line_obj.create( - { - 'move_id': move_id.id, + 'journal_id': self.journal.id, + 'company_id': self.company_id, + 'line_ids': [(0, 0, { 'name': '/', 'debit': amount, 'credit': 0, - 'account_id': account2.id, - 'company_id': company_id, - 'partner_id': self.ref('base.res_partner_1') - if with_partner else False - } - ) - return move_line_id.move_id + 'account_id': self.account_customer.id, + 'company_id': self.company_id, + 'partner_id': with_partner and self.partner.id + }), (0, 0, { + 'name': '/', + 'debit': 0, + 'credit': amount, + 'company_id': self.company_id, + 'account_id': self.account_sale.id, + })] + } + return self.move_obj.create(move_vals) - def _close_period(self, period_id): - self.env.cr.execute('update account_journal_period ' - 'set state=%s where period_id=%s', - ('done', period_id)) - self.env.cr.execute('update account_period ' - 'set state=%s where id=%s', - ('done', period_id)) - self.env.invalidate_all() + def _move_str(self, move): + return ''.join(['%.2f%.2f%s' % ( + x.debit, x.credit, x.account_id == self.account_sale and + ':SALE_' or ':CUSTOMER_') + for x in move.line_ids.sorted(key=lambda r: r.account_id.id)]) def test_reverse(self): - move = self._create_move(with_partner=False) - company_id = self.env.ref('base.main_company').id - account1 = self.env['account.account'].search( - [('company_id', '=', company_id), ('type', '=', 'other')])[0] - movestr = ''.join(['%.2f%.2f%s' % (x.debit, x.credit, - x.account_id == account1 and - 'aaaa' or 'bbbb') - for x in move.line_id]) - self.assertEqual(movestr, '100.000.00bbbb0.00100.00aaaa') - yesterday_date = datetime( - year=time.localtime().tm_year, month=3, day=3 - ) - yesterday = fields.Date.to_string(yesterday_date) - reversed_move_ids = move.create_reversals(yesterday) - reversed_moves = self.env['account.move'].browse(reversed_move_ids) - movestr_reversed = ''.join( - ['%.2f%.2f%s' % (x.debit, x.credit, - x.account_id == account1 and 'aaaa' or 'bbbb') - for x in reversed_moves.line_id]) - self.assertEqual(movestr_reversed, '0.00100.00bbbb100.000.00aaaa') - - def test_reverse_closed_period(self): - move_period = self.env.ref('account.period_0') - move = self._create_move(with_partner=False, period=move_period) - self._close_period(move_period.id) - reversal_period = self.env.ref('account.period_1') - move.create_reversals(reversal_date=reversal_period.date_start, - reversal_period_id=reversal_period.id) + move = self._create_move() + self.assertEqual( + self._move_str(move), '0.00100.00:SALE_100.000.00:CUSTOMER_') + rev = move.create_reversals() + self.assertEqual(len(rev), 1) + self.assertEqual( + self._move_str(rev), '100.000.00:SALE_0.00100.00:CUSTOMER_') diff --git a/account_reversal/views/account_move_view.xml b/account_reversal/views/account_move_view.xml new file mode 100644 index 000000000..09863ab0b --- /dev/null +++ b/account_reversal/views/account_move_view.xml @@ -0,0 +1,59 @@ + + + + + + Add to_be_reversed column + account.move + + + + + + + + + + Add to_be_reversed and reversal_id fields + account.move + + + + + + + + + + + + Add to_be_reversed filter + account.move + + + + + + + + + + + + + diff --git a/account_reversal/wizard/__init__.py b/account_reversal/wizard/__init__.py index fc857770b..5f47c9160 100644 --- a/account_reversal/wizard/__init__.py +++ b/account_reversal/wizard/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from . import account_move_reverse diff --git a/account_reversal/wizard/account_move_reverse.py b/account_reversal/wizard/account_move_reverse.py index 9cccd1ab1..c87ab807b 100644 --- a/account_reversal/wizard/account_move_reverse.py +++ b/account_reversal/wizard/account_move_reverse.py @@ -1,122 +1,78 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Account reversal module for OpenERP -# Copyright (C) 2011 Akretion (http://www.akretion.com). All Rights Reserved -# @author Alexis de Lattre -# Copyright (c) 2012-2013 Camptocamp SA (http://www.camptocamp.com) -# @author Guewen Baconnier -# -# -# 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 . -# -############################################################################## +# Copyright 2011 Alexis de Lattre +# Copyright 2012-2013 Guewen Baconnier (Camptocamp) +# Copyright 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp import api, fields, models, _ -class account_move_reversal(orm.TransientModel): +class AccountMoveReverse(models.TransientModel): _name = "account.move.reverse" _description = "Create reversal of account moves" - _columns = { - 'date': fields.date( - 'Reversal Date', - required=True, - help="Enter the date of the reversal account entries. " - "By default, OpenERP proposes the first day of " - "the period following the period of the move to reverse."), - 'period_id': fields.many2one( - 'account.period', - 'Reversal Period', - help="If empty, take the period of the date."), - 'journal_id': fields.many2one( - 'account.journal', - 'Reversal Journal', - help='If empty, uses the journal of the journal entry ' - 'to be reversed.'), - 'move_prefix': fields.char( - 'Entries Ref. Prefix', - help="Prefix that will be added to the 'Ref' of the journal " - "entry to be reversed to create the 'Ref' of the " - "reversal journal entry (no space added after the prefix)."), - 'move_line_prefix': fields.char( - 'Items Name Prefix', - help="Prefix that will be added to the name of the journal " - "item to be reversed to create the name of the reversal " - "journal item (a space is added after the prefix)."), - 'reconcile': fields.boolean('Reconcile'), - } + def _default_date(self): + active_id = (self.env.context.get('active_id') or + self.env.context.get('active_ids', [None])[0]) + move = self.env['account.move'].browse(active_id) + return move.date or fields.Date.today() - def _next_period_first_date(self, cr, uid, context=None): - if context is None: - context = {} - res = False - period_ctx = context.copy() - period_ctx['account_period_prefer_normal'] = True - period_obj = self.pool.get('account.period') - assert context['active_model'] == 'account.move' - to_reverse_move = self.pool['account.move'].browse( - cr, uid, context['active_id'], context=context) - next_period_id = period_obj.next( - cr, uid, to_reverse_move.period_id, 1, context=context) - if next_period_id: - next_period = period_obj.browse( - cr, uid, next_period_id, context=context) - res = next_period.date_start - return res + def _default_journal_id(self): + active_id = (self.env.context.get('active_id') or + self.env.context.get('active_ids', [None])[0]) + move = self.env['account.move'].browse(active_id) + return move.journal_id.id - _defaults = { - 'date': _next_period_first_date, - 'move_line_prefix': 'REV -', - 'reconcile': True, - } + date = fields.Date( + string="Reversal Date", required=True, default=_default_date, + help="Enter the date of the reversal account entries. " + "By default, Odoo proposes the same date of the move to reverse.") + journal_id = fields.Many2one( + comodel_name='account.journal', string="Reversal Journal", + default=_default_journal_id, + help="Enter the date of the reversal account entries. " + "If empty, Odoo uses the same journal of the move to reverse.") + move_prefix = fields.Char( + string="Entries Ref. Prefix", default="REV:", + help="Prefix that will be added to the 'Ref' of the reversal account " + "entries. If empty, Odoo uses the Ref of the move to reverse. " + "(NOTE: A space is added after the prefix).") + line_prefix = fields.Char( + string="Items Name Prefix", default="REV:", + help="Prefix that will be added to the 'Name' of the reversal account " + "entrie items. If empty, Odoo uses the same name of the move " + "line to reverse. (NOTE: A space is added after the prefix).") + post = fields.Boolean( + string="Post", default=True, + help="Mark this if you want to post reversal move") + reconcile = fields.Boolean( + string="Reconcile", default=True, + help="Mark this if you want to reconcile items of both moves.") - def action_reverse(self, cr, uid, ids, context=None): - if context is None: - context = {} - assert 'active_ids' in context, "active_ids missing in context" - - form = self.read(cr, uid, ids, context=context)[0] - - move_obj = self.pool.get('account.move') - move_ids = context['active_ids'] - - period_id = form['period_id'][0] if form.get('period_id') else False - journal_id = form['journal_id'][0] if form.get('journal_id') else False - reconcile = form['reconcile'] if form.get('reconcile') else False - reversed_move_ids = move_obj.create_reversals( - cr, uid, - move_ids, - form['date'], - reversal_period_id=period_id, - reversal_journal_id=journal_id, - move_prefix=form['move_prefix'], - move_line_prefix=form['move_line_prefix'], - reconcile=reconcile, - context=context) - - action = self.pool['ir.actions.act_window'].for_xml_id( - cr, uid, 'account', 'action_move_journal_line') - action['name'] = _('Reversal Entries') - action['context'] = unicode({'search_default_to_be_reversed': 0}) - if len(reversed_move_ids) == 1: - action['res_id'] = reversed_move_ids[0] - action['view_mode'] = 'form,tree' - action['views'] = False - action['view_id'] = False + @api.multi + def action_reverse(self): + moves = self.env['account.move'] + for wizard in self: + orig = moves.browse(self.env.context.get('active_ids')) + moves |= orig.create_reversals( + date=wizard.date, journal=wizard.journal_id, + move_prefix=wizard.move_prefix, line_prefix=wizard.line_prefix, + post=wizard.post, reconcile=wizard.reconcile) + action = { + 'name': _('Reverse moves'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'res_model': 'account.move', + 'context': {'search_default_to_be_reversed': 0}, + } + if len(moves) == 1: + action.update({ + 'view_mode': 'form,tree', + 'res_id': moves.id, + }) else: - action['domain'] = unicode([('id', 'in', reversed_move_ids)]) + action.update({ + 'view_mode': 'tree,form', + 'domain': [('id', 'in', moves.ids)], + }) return action diff --git a/account_reversal/wizard/account_move_reverse_view.xml b/account_reversal/wizard/account_move_reverse_view.xml index 2512b9dc8..0fa6704ea 100644 --- a/account_reversal/wizard/account_move_reverse_view.xml +++ b/account_reversal/wizard/account_move_reverse_view.xml @@ -1,47 +1,51 @@ - - + - - account.move.reverse.form - account.move.reverse - -
-
-
+ + account.move.reverse.form + account.move.reverse + +
+
+
- - Reverse Entries - client_action_multi - account.move - - + + Reverse Entries + account.move.reverse + form + + new + -
-
+ + + + +