← Back to team overview

banking-addons-team team mailing list archive

Re: [Merge] lp:~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-cancel-line-lep into lp:banking-addons/bank-statement-reconcile-7.0

 

Review: Approve no test, code review

LGTM

Diff comments:

> === added directory 'account_statement_cancel_line'
> === added file 'account_statement_cancel_line/__init__.py'
> --- account_statement_cancel_line/__init__.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/__init__.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,25 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Account Statement Cancel Line."""
> +
> +import statement  # noqa
> +import statement_line  # noqa
> +import wizard  # noqa
> 
> === added file 'account_statement_cancel_line/__openerp__.py'
> --- account_statement_cancel_line/__openerp__.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/__openerp__.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,74 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone                                                  #
> +#   Copyright 2014 Camptocamp SA                                              #
> +#                                                                             #
> +#   Inspired by module account_banking by EduSense BV, Therp BV, Smile        #
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +{
> +    'name': "Account Statement Cancel Line",
> +    'version': '0.3',
> +    'author': 'Camptocamp',
> +    'maintainer': 'Camptocamp',
> +    'category': 'Finance',
> +    'complexity': 'normal',
> +    'depends': [
> +        'account',
> +        'account_statement_ext',
> +        'account_default_draft_move',
> +        'account_statement_base_completion',
> +    ],
> +    'description': """
> +        Account Statement Cancel Line
> +
> +        This module allows to cancel one line of the statement without
> +        cancelling the whole thing.
> +
> +        To do that, a state is added to the statement line.
> +
> +        When the user confirms or cancels the whole statement, we keep the
> +        previous functionality, and then we change the state in all statement
> +        lines. We also add a warning if any lines are reconciled. If no lines
> +        are reconciled, we show a generic warning because the operation could
> +        take a long time.
> +
> +        When the user confirms or cancels a statement line, we update the state
> +        of the line, and if necessary we update the state of the whole
> +        statement, too.
> +
> +        If the user tries to cancel a line that is reconciled, we ask for
> +        confirmation before proceeding.
> +    """,
> +    'website': 'http://www.camptocamp.com',
> +    'init_xml': [],
> +    'update_xml': [
> +        'statement_view.xml',
> +        'wizard/cancel_statement_view.xml',
> +        'wizard/cancel_statement_line_view.xml',
> +    ],
> +    'demo_xml': [],
> +    'test': [
> +        'test/cancel_line.yml',
> +        'test/test_confirm_last_line_balance_check.yml',
> +        'test/test_confirm_last_line_no_balance_check.yml',
> +        'test/confirm_statement_no_double_moves.yml',
> +    ],
> +    'installable': True,
> +    'images': [],
> +    'license': 'AGPL-3',
> +}
> 
> === added directory 'account_statement_cancel_line/i18n'
> === added file 'account_statement_cancel_line/i18n/account_statement_cancel_line.pot'
> --- account_statement_cancel_line/i18n/account_statement_cancel_line.pot	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/i18n/account_statement_cancel_line.pot	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,97 @@
> +# Translation of OpenERP Server.
> +# This file contains the translation of the following modules:
> +#	* account_statement_cancel_line
> +#
> +msgid ""
> +msgstr ""
> +"Project-Id-Version: OpenERP Server 7.0\n"
> +"Report-Msgid-Bugs-To: \n"
> +"POT-Creation-Date: 2014-02-17 16:46+0000\n"
> +"PO-Revision-Date: 2014-02-17 16:46+0000\n"
> +"Last-Translator: <>\n"
> +"Language-Team: \n"
> +"MIME-Version: 1.0\n"
> +"Content-Type: text/plain; charset=UTF-8\n"
> +"Content-Transfer-Encoding: \n"
> +"Plural-Forms: \n"
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_account_bank_statement_line
> +msgid "Bank Statement Line"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Some entries are already reconciled. Do you want to unreconcile them and proceed?"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:account.bank.statement:0
> +msgid "Cancel transaction"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_wizard_cancel_statement
> +msgid "Cancel Statement"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_account_bank_statement
> +msgid "Bank Statement"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_wizard_cancel_statement_line
> +msgid "Cancel Statement Line"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: field:account.bank.statement.line,state:0
> +msgid "State"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Reconciled Entries"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: selection:account.bank.statement.line,state:0
> +msgid "Draft"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: selection:account.bank.statement.line,state:0
> +msgid "Confirmed"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Cancel"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:account.bank.statement:0
> +msgid "Confirm transaction"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Unreconcile"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "or"
> +msgstr ""
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Unreconciliation"
> +msgstr ""
> 
> === added file 'account_statement_cancel_line/i18n/fr.po'
> --- account_statement_cancel_line/i18n/fr.po	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/i18n/fr.po	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,97 @@
> +# Translation of OpenERP Server.
> +# This file contains the translation of the following modules:
> +#	* account_statement_cancel_line
> +#
> +msgid ""
> +msgstr ""
> +"Project-Id-Version: OpenERP Server 7.0\n"
> +"Report-Msgid-Bugs-To: \n"
> +"POT-Creation-Date: 2014-02-17 15:59+0000\n"
> +"PO-Revision-Date: 2014-02-17 15:59+0000\n"
> +"Last-Translator: <>\n"
> +"Language-Team: \n"
> +"MIME-Version: 1.0\n"
> +"Content-Type: text/plain; charset=UTF-8\n"
> +"Content-Transfer-Encoding: \n"
> +"Plural-Forms: \n"
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_account_bank_statement_line
> +msgid "Bank Statement Line"
> +msgstr "Ligne de relevé bancaire"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Some entries are already reconciled. Do you want to unreconcile them and proceed?"
> +msgstr "Certaines écritures sont déja léttrées. Voulez-vous annuler définitivement tout les léttrages et poursuivre?"
> +
> +#. module: account_statement_cancel_line
> +#: view:account.bank.statement:0
> +msgid "Cancel transaction"
> +msgstr "Annuler ligne"
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_wizard_cancel_statement
> +msgid "Cancel Statement"
> +msgstr "Annuler le relevé"
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_account_bank_statement
> +msgid "Bank Statement"
> +msgstr "Relevé bancaire"
> +
> +#. module: account_statement_cancel_line
> +#: model:ir.model,name:account_statement_cancel_line.model_wizard_cancel_statement_line
> +msgid "Cancel Statement Line"
> +msgstr "Annuler ligne de relevé"
> +
> +#. module: account_statement_cancel_line
> +#: field:account.bank.statement.line,state:0
> +msgid "State"
> +msgstr "Etat"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Reconciled Entries"
> +msgstr "Lignes léttrées"
> +
> +#. module: account_statement_cancel_line
> +#: selection:account.bank.statement.line,state:0
> +msgid "Draft"
> +msgstr "Brouillon"
> +
> +#. module: account_statement_cancel_line
> +#: selection:account.bank.statement.line,state:0
> +msgid "Confirmed"
> +msgstr "Confirmée"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Cancel"
> +msgstr "Annuler"
> +
> +#. module: account_statement_cancel_line
> +#: view:account.bank.statement:0
> +msgid "Confirm transaction"
> +msgstr "Confirmer ligne"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Unreconcile"
> +msgstr "Déléttrer"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "or"
> +msgstr "ou"
> +
> +#. module: account_statement_cancel_line
> +#: view:wizard.cancel.statement:0
> +#: view:wizard.cancel.statement.line:0
> +msgid "Unreconciliation"
> +msgstr "Déléttrage"
> 
> === added directory 'account_statement_cancel_line/migrations'
> === added directory 'account_statement_cancel_line/migrations/0.3'
> === added file 'account_statement_cancel_line/migrations/0.3/post-set-statement-line-state.py'
> --- account_statement_cancel_line/migrations/0.3/post-set-statement-line-state.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/migrations/0.3/post-set-statement-line-state.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,38 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone                                                  #
> +#   Copyright 2014 Camptocamp SA                                              #
> +#                                                                             #
> +#   Inspired by module account_banking by EduSense BV, Therp BV, Smile        #
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +
> +__name__ = ("account.bank.statement.line:: set new field 'state' to "
> +            "confirmed for all statement lines belonging to confirmed "
> +            "statements")
> +
> +
> +def migrate(cr, version):
> +    """This module adds the field state to the statement line. Here we set it
> +    correctly on existing statements. The names, and so this migration, are
> +    intentionally kept in sync with the account_banking module."""
> +    cr.execute("UPDATE account_bank_statement_line as sl "
> +               " SET state = 'confirmed'"
> +               " FROM account_bank_statement as s "
> +               " WHERE sl.statement_id = s.id "
> +               " AND s.state = 'confirm' "
> +               )
> 
> === added file 'account_statement_cancel_line/statement.py'
> --- account_statement_cancel_line/statement.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/statement.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,118 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Account Statement Cancel Line."""
> +
> +from openerp.osv import orm
> +
> +
> +class Statement(orm.Model):
> +
> +    """Bank Statement.
> +
> +    Minimal changes to allow cancelling single lines and checking if there are
> +    any lines that are already reconciled.
> +
> +    """
> +
> +    _inherit = "account.bank.statement"
> +
> +    def button_confirm_bank(self, cr, uid, ids, context=None):
> +        """If all lines are draft, change their state.
> +        Otherwise, confirm line by line to avoid duplicate moves.
> +        Return super.
> +
> +        """
> +        st_line_obj = self.pool['account.bank.statement.line']
> +
> +        statement_ids_fully_confirm = []
> +        for st in self.browse(cr, uid, ids, context=context):
> +            if all(l.state == 'draft' for l in st.line_ids):
> +                statement_ids_fully_confirm.append(st.id)
> +                st_line_obj.write(cr, uid, [l.id for l in st.line_ids], {
> +                    'state': 'confirmed'
> +                }, context=context)
> +            else:
> +                st_line_obj.confirm(cr, uid, [l.id for l in st.line_ids],
> +                                    context=context)
> +
> +        if statement_ids_fully_confirm:
> +            return super(Statement, self).button_confirm_bank(
> +                cr, uid, statement_ids_fully_confirm, context)
> +        else:
> +            return True
> +
> +    def button_cancel(self, cr, uid, ids, context=None):
> +        """Check if there is any reconciliation. Return action."""
> +        st_line_obj = self.pool['account.bank.statement.line']
> +        for statement in self.browse(cr, uid, ids, context=context):
> +            ctx = context.copy()
> +            ctx['default_reconcile_warning'] = st_line_obj.has_reconciliation(
> +                cr,
> +                uid,
> +                [line.id for line in statement.line_ids],
> +                context=context)
> +            return {
> +                'type': 'ir.actions.act_window',
> +                'res_model': 'wizard.cancel.statement',
> +                'view_type': 'form',
> +                'view_mode': 'form',
> +                'target': 'new',
> +                'context': ctx,
> +            }
> +
> +        self.do_cancel(cr, uid, ids, context=context)
> +
> +    def do_cancel(self, cr, uid, ids, context=None):
> +        """Change the state on the statement lines. Return super.
> +
> +        This method is called directly when there are no reconciliations, or
> +        from the warning wizard, if there are reconciliations.
> +
> +        """
> +        st_line_obj = self.pool['account.bank.statement.line']
> +        for st_data in self.read(cr, uid, ids, ['line_ids'], context=context):
> +            st_line_obj.write(cr, uid, st_data['line_ids'], {
> +                'state': 'draft'
> +            }, context=context)
> +
> +        return super(Statement, self).button_cancel(
> +            cr, uid, ids, context)
> +
> +    def confirm_statement_from_lines(self, cr, uid, ids, context=None):
> +        """If all lines are confirmed, so is the whole statement.
> +
> +        Return True if we changed anything.
> +
> +        """
> +        need_to_update_view = False
> +        for statement in self.browse(cr, uid, ids, context=context):
> +            if all(line.state == 'confirmed' for line in statement.line_ids):
> +                self.write(cr, uid, [statement.id], {
> +                    'state': 'confirm'
> +                }, context=context)
> +                need_to_update_view = True
> +                self.balance_check(
> +                    cr,
> +                    uid,
> +                    statement.id,
> +                    journal_type=statement.journal_id.type,
> +                    context=context)
> +        return need_to_update_view
> 
> === added file 'account_statement_cancel_line/statement_line.py'
> --- account_statement_cancel_line/statement_line.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/statement_line.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,213 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Account Statement Cancel Line."""
> +
> +from openerp.osv import fields, orm
> +
> +from openerp.tools.translate import _
> +
> +
> +class StatementLine(orm.Model):
> +
> +    """Add a state to the statement line."""
> +
> +    _inherit = "account.bank.statement.line"
> +
> +    _columns = {
> +        'state': fields.selection(
> +            [('draft', 'Draft'), ('confirmed', 'Confirmed')],

function will allows to be more polite to get selection value. But neat picks

> +            'State',
> +            readonly=True,
> +            required=True
> +        ),
> +    }
> +
> +    _defaults = {
> +        'state': 'draft',
> +    }
> +
> +    def confirm(self, cr, uid, ids, context=None):
> +        """Confirm just one statement line, return action.
> +
> +        The module account_banking does have a similar method, but at the
> +        moment it uses a different logic (for example, it uses vouchers, where
> +        the bank-statement-reconcile branch does not).
> +
> +        """
> +        if context is None:
> +            context = {}
> +        local_ctx = context.copy()
> +        # if account_constraints is installed, we need to tell it that moves
> +        # are being created by a statement, which is OK.
> +        # The module tries to prevent direct changes to the moves created by
> +        # bank statements.
> +        local_ctx['from_parent_object'] = True
> +
> +        statement_pool = self.pool.get('account.bank.statement')
> +        res = {}
> +
> +        for st_line in self.browse(cr, uid, ids, context):
> +            if st_line.state != 'draft':
> +                continue
> +            st = st_line.statement_id
> +            curr_id = st.journal_id.company_id.currency_id.id
> +
> +            st_number = st.name
> +            st_line_number = statement_pool.get_next_st_line_number(
> +                cr, uid, st_number, st_line, context)
> +
> +            # We pass the local_ctx so that account_constraints allows us to
> +            # work on the moves generated by the bank statement
> +            statement_pool.create_move_from_st_line(
> +                cr,
> +                uid,
> +                st_line.id,
> +                curr_id,
> +                st_line_number,
> +                local_ctx)
> +            self.write(cr, uid, st_line.id, {
> +                'state': 'confirmed'
> +            }, context)
> +            if statement_pool.confirm_statement_from_lines(cr, uid, [st.id],
> +                                                           context=context):
> +                # to see that the state of the statement has changed, we need
> +                # to update the whole view. Do that only if necessary.
> +                res = {
> +                    'type': 'ir.actions.client',
> +                    'tag': 'reload',
> +                }
> +
> +        return res
> +
> +    def has_reconciliation(self, cr, uid, ids, context=None):
> +        """Check if the line has some reconciliation. Return boolean."""
> +        if context is None:
> +            context = {}
> +
> +        for st_line in self.browse(cr, uid, ids, context=context):
> +            for move in st_line.move_ids:
> +                for move_line in move.line_id:
> +                    if move_line.reconcile:
> +                        # aha! we have some reconciliation!
> +                        return True
> +
> +        # no reconciliation to worry about
> +        return False
> +
> +    def button_cancel(self, cr, uid, ids, context=None):
> +        """Check if a line is reconciled, and cancel it. Return action."""
> +        if context is None:
> +            context = {}
> +
> +        if self.has_reconciliation(cr, uid, ids, context=context):
> +            # ask confirmation, we have some reconciliation already
> +            return {
> +                'type': 'ir.actions.act_window',
> +                'res_model': 'wizard.cancel.statement.line',
> +                'view_type': 'form',
> +                'view_mode': 'form',
> +                'target': 'new',
> +                'context': context,
> +            }
> +
> +        # no reconciliation to worry about: we cancel our lines directly then
> +        return self.cancel(cr, uid, ids, context=context)
> +
> +    def cancel(self, cr, uid, ids, context=None):
> +        """Cancel one statement line, return action.
> +
> +        This is again similar to the method cancel in the account_banking
> +        module.
> +
> +        """
> +        if context is None:
> +            context = {}
> +        local_ctx = context.copy()
> +        # if account_constraints is installed, we need to tell it that moves
> +        # are being created by a statement, which is OK.
> +        # The module tries to prevent direct changes to the moves created by
> +        # bank statements.
> +        local_ctx['from_parent_object'] = True
> +
> +        move_pool = self.pool['account.move']
> +        statement_pool = self.pool['account.bank.statement']
> +
> +        st_line_ids = []
> +
> +        # to avoid duplicates if all lines come from the same statement
> +        statement_ids = set()
> +
> +        move_unlink_ids = []
> +        # harvest ids for various actions
> +        for st_line in self.browse(cr, uid, ids, context):
> +            if st_line.state != 'confirmed':
> +                continue
> +
> +            for move in st_line.move_ids:
> +                # We allow for people canceling and removing
> +                # the associated payments, which can lead to confirmed
> +                # statement lines without an associated move
> +                move_unlink_ids.append(move.id)
> +                # do we need to check that?
> +                if move.state != 'draft':
> +                    raise orm.except_orm(
> +                        _('Confirmed Journal Entry'),
> +                        _('You cannot delete a confirmed Statement Line '
> +                          'associated to a Journal Entry that is posted.'))
> +            st_line_ids.append(st_line.id)
> +            if st_line.statement_id.state != 'draft':
> +                statement_ids.add(st_line.statement_id.id)
> +
> +        move_pool.button_cancel(
> +            cr, uid, move_unlink_ids, context=context)
> +
> +        move_pool.unlink(cr, uid, move_unlink_ids, context=local_ctx)
> +        self.write(cr, uid, st_line_ids, {
> +            'state': 'draft',
> +            'already_completed': False
> +        }, context=context)
> +        if statement_ids:
> +            # if we cancel one or more lines, the statement goes back to draft,
> +            # too
> +            statement_pool.write(cr, uid, list(statement_ids), {
> +                'state': 'draft'
> +            }, context=context)
> +            # then we manually update the view of the statement
> +            return {
> +                'type': 'ir.actions.client',
> +                'tag': 'reload',
> +            }
> +        else:
> +            # no need to update the view then
> +            return {}
> +
> +    def unlink(self, cr, uid, ids, context=None):
> +        """Don't allow deletion of a confirmed statement line. Return super."""
> +        if type(ids) is int:
> +            ids = [ids]
> +        for line in self.browse(cr, uid, ids, context=context):
> +            if line.state == 'confirmed':
> +                raise orm.except_orm(
> +                    _('Confirmed Statement Line'),
> +                    _("You cannot delete a confirmed Statement Line"
> +                      ": '%s'") % line.name)
> +        return super(StatementLine, self).unlink(
> +            cr, uid, ids, context=context)
> 
> === added file 'account_statement_cancel_line/statement_view.xml'
> --- account_statement_cancel_line/statement_view.xml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/statement_view.xml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,28 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<openerp>
> +    <data>
> +
> +        <record id="view_bank_statement_form_cancel_line" model="ir.ui.view">
> +            <field name="name">account.bank.statement.form.</field>
> +            <field name="inherit_id" ref="account.view_bank_statement_form" />
> +            <field name="model">account.bank.statement</field>
> +            <field name="arch" type="xml">
> +                <data>
> +                    <xpath expr="//field[@name='line_ids']/tree/field[@name='amount']"
> +                           position="after">
> +                        <field name="state"/>
> +                        <button name="confirm" states="draft"
> +                                string="Confirm transaction"
> +                                icon="gtk-ok"
> +                                type="object"/>
> +                        <button name="button_cancel" states="confirmed"
> +                                string="Cancel transaction"
> +                                icon="gtk-cancel"
> +                                type="object"/>
> +                    </xpath>
> +                </data>
> +            </field>
> +        </record>
> +
> +    </data>
> +</openerp>
> 
> === added directory 'account_statement_cancel_line/test'
> === added file 'account_statement_cancel_line/test/cancel_line.yml'
> --- account_statement_cancel_line/test/cancel_line.yml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/test/cancel_line.yml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,80 @@
> +-
> +  In order to test the cancellation of statement lines, I need a statement
> +  profile.
> +-
> +  !record {model: account.statement.profile, id: profile_test}:
> +    name: Bank EUR Profile for automatic checks
> +    journal_id: account.bank_journal
> +    commission_account_id: account.a_expense
> +    company_id: base.main_company
> +-
> +  Now I create a statement. I create statment lines separately because I need
> +  to find each one by XML id
> +-
> +  !record {model: account.bank.statement, id: statement_test}:
> +    name: My Statement
> +    profile_id: profile_test
> +    company_id: base.main_company
> +-
> +  I create a first statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_1}:
> +    name: line1
> +    statement_id: statement_test
> +    ref: ref1
> +    date: '2014-01-20'
> +    amount: 100.0
> +-
> +  I create a second statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_2}:
> +    name: line2
> +    statement_id: statement_test
> +    ref: ref2
> +    date: '2014-01-25'
> +    amount: 200.0
> +-
> +  I check that the state of the statement is "Draft"
> +-
> +  !assert {model: account.bank.statement, id: statement_test}:
> +    - state == 'draft'
> +-
> +  I confirm the statement
> +-
> +  !python {model: account.bank.statement}: |
> +    result = self.button_confirm_bank(cr, uid, [ref("statement_test")])
> +-
> +  I check that the state of the statement is "Closed"
> +-
> +  !assert {model: account.bank.statement, id: statement_test}:
> +    - state == 'confirm'
> +-
> +  I check that the state of the statement line is "Confirmed"
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_1}:
> +    - state == 'confirmed'
> +-
> +  I check that a move was generated
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_1}:
> +    - move_ids
> +-
> +  Now I cancel a statement line
> +-
> +  !python {model: account.bank.statement.line}: |
> +    result = self.button_cancel(cr, uid, [ref("statement_line_1")])
> +-
> +  I check that the state of the statement went back to "Draft"
> +-
> +  !assert {model: account.bank.statement, id: statement_test}:
> +    - state == 'draft'
> +-
> +  I also check that the state of the statement line went back to "Draft"
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_1}:
> +    - state == 'draft'
> +-
> +  And the move is not there anymore
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_1}:
> +    - move_ids == []
> 
> === added file 'account_statement_cancel_line/test/confirm_statement_no_double_moves.yml'
> --- account_statement_cancel_line/test/confirm_statement_no_double_moves.yml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/test/confirm_statement_no_double_moves.yml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,70 @@
> +-
> +  I want to check that if I confirm a line and then the whole statement,
> +  no duplicate moves are created.
> +  First, I need a statement profile.
> +-
> +  !record {model: account.statement.profile, id: profile_test_10}:
> +    name: Another Bank EUR Profile for automatic checks
> +    journal_id: account.bank_journal
> +    commission_account_id: account.a_expense
> +    company_id: base.main_company
> +-
> +  Now I create a statement. I create statment lines separately because I need
> +  to find each one by XML id
> +-
> +  !record {model: account.bank.statement, id: statement_test_10}:
> +    name: My Statement
> +    profile_id: profile_test_10
> +    company_id: base.main_company
> +-
> +  I create a first statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_11}:
> +    name: line11
> +    statement_id: statement_test_10
> +    ref: ref11
> +    date: '2014-01-20'
> +    amount: 100.0
> +-
> +  I create a second statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_12}:
> +    name: line12
> +    statement_id: statement_test_10
> +    ref: ref12
> +    date: '2014-01-25'
> +    amount: 200.0
> +-
> +  Now I confirm only the first statement line
> +-
> +  !python {model: account.bank.statement.line}: |
> +    result = self.confirm(cr, uid, [ref("statement_line_11")])
> +-
> +  I check that the state of the statement is still "Draft"
> +-
> +  !assert {model: account.bank.statement, id: statement_test_10}:
> +    - state == 'draft'
> +-
> +  I confirm the statement
> +-
> +  !python {model: account.bank.statement}: |
> +    result = self.button_confirm_bank(cr, uid, [ref("statement_test_10")])
> +-
> +  I check that the state of the statement is "Closed"
> +-
> +  !assert {model: account.bank.statement, id: statement_test_10}:
> +    - state == 'confirm'
> +-
> +  I check that a move was generated for the first statment line
> +  and that the state is confirmed
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_11}:
> +    - len(move_ids) == 1
> +    - state == 'confirmed'
> +-
> +  I check that a move was generated for the second statment line
> +  and that the state is confirmed
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_12}:
> +    - len(move_ids) == 1
> +    - state == 'confirmed'
> 
> === added file 'account_statement_cancel_line/test/test_confirm_last_line_balance_check.yml'
> --- account_statement_cancel_line/test/test_confirm_last_line_balance_check.yml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/test/test_confirm_last_line_balance_check.yml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,42 @@
> +-
> +  I want to check that the behaviour when I confirm the only line of a
> +  statement that is draft.
> +-
> +  I start with a profile
> +-
> +  !record {model: account.statement.profile, id: profile_test3}:
> +    name: Profile for automatic checks
> +    balance_check: True
> +    journal_id: account.bank_journal
> +    commission_account_id: account.a_expense
> +-
> +  Now I create a statement.
> +-
> +  !record {model: account.bank.statement, id: statement_test3}:
> +    name: My Statement
> +    profile_id: profile_test3
> +    company_id: base.main_company
> +    balance_start: 100.0
> +    balance_end_real: 150.0
> +-
> +  I create a statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_3}:
> +    name: line1
> +    statement_id: statement_test3
> +    ref: line1
> +    date: '2014-01-20'
> +    amount: 10.0
> +-
> +  Now I confirm the statement line. That should not pass the balance check
> +-
> +  !python {model: account.bank.statement.line}: |
> +    # i.e. assertRaises 
> +    from openerp.osv.osv import except_osv
> +    try:
> +        self.confirm(cr, uid, [ref("statement_line_3")])
> +    except except_osv as exc:
> +        print exc.args
> +        assert u'The statement balance is incorrect' in exc.args[1], 'We got an error which is not what we expected'
> +    else:
> +        raise AssertionError('Balance check should have blocked this.')
> 
> === added file 'account_statement_cancel_line/test/test_confirm_last_line_no_balance_check.yml'
> --- account_statement_cancel_line/test/test_confirm_last_line_no_balance_check.yml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/test/test_confirm_last_line_no_balance_check.yml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,44 @@
> +-
> +  I want to check that the behaviour when I confirm the only line of a
> +  statement that is draft.
> +-
> +  I start with a profile
> +-
> +  !record {model: account.statement.profile, id: profile_test4}:
> +    name: Profile for automatic checks
> +    balance_check: False
> +    journal_id: account.bank_journal
> +    commission_account_id: account.a_expense
> +-
> +  Now I create a statement.
> +-
> +  !record {model: account.bank.statement, id: statement_test4}:
> +    name: My Statement
> +    profile_id: profile_test4
> +    company_id: base.main_company
> +    balance_start: 100.0
> +    balance_end_real: 150.0
> +-
> +  I create a statement line
> +-
> +  !record {model: account.bank.statement.line, id: statement_line_4}:
> +    name: line1
> +    statement_id: statement_test4
> +    ref: line1
> +    date: '2014-01-20'
> +    amount: 10.0
> +-
> +  Now I confirm the statement line
> +-
> +  !python {model: account.bank.statement.line}: |
> +    result = self.confirm(cr, uid, [ref("statement_line_4")])
> +-
> +  The line should be confirmed
> +-
> +  !assert {model: account.bank.statement.line, id: statement_line_4}:
> +    - state == 'confirmed'
> +-
> +  And the statement should be confirmed as well
> +-
> +  !assert {model: account.bank.statement, id: statement_test4}:
> +    - state == 'confirm'
> 
> === added directory 'account_statement_cancel_line/tests'
> === added directory 'account_statement_cancel_line/wizard'
> === added file 'account_statement_cancel_line/wizard/__init__.py'
> --- account_statement_cancel_line/wizard/__init__.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/__init__.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,24 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Wizard for asking the confirmation when some move is reconciled."""
> +
> +import cancel_statement  # noqa
> +import cancel_statement_line  # noqa
> 
> === added file 'account_statement_cancel_line/wizard/cancel_line.py'
> --- account_statement_cancel_line/wizard/cancel_line.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/cancel_line.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,46 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Wizard to Cancel a Statement Line."""
> +
> +from openerp.osv import orm
> +
> +
> +class wizard_cancel_statement_line(orm.TransientModel):
> +
> +    """Wizard to Cancel a Statement Line."""
> +
> +    _name = "wizard.cancel.statement.line"
> +    _description = "Cancel Statement Line"
> +    _columns = {
> +    }
> +
> +    def unreconcile(self, cr, uid, ids, context=None):
> +        """Proceed and cancel the statement line, return Action.
> +
> +        This will delete the move.line and the reconciliation.
> +
> +        """
> +        return self.pool['account.bank.statement.line'].cancel(
> +            cr,
> +            uid,
> +            context['active_ids'],
> +            context=context
> +        )
> 
> === added file 'account_statement_cancel_line/wizard/cancel_statement.py'
> --- account_statement_cancel_line/wizard/cancel_statement.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/cancel_statement.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,51 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Wizard to Cancel a Statement."""
> +
> +from openerp.osv import orm, fields
> +
> +
> +class wizard_cancel_statement(orm.TransientModel):
> +
> +    """Wizard to Cancel a Statement."""
> +
> +    _name = "wizard.cancel.statement"
> +    _description = "Cancel Statement"
> +    _columns = {
> +        'reconcile_warning': fields.boolean(
> +            'Show reconcile warning',
> +            help='This is a hidden field set with a default in the context '
> +            'to choose between two different warning messages in the view.'
> +            ),
> +    }
> +
> +    def do_cancel_button(self, cr, uid, ids, context=None):
> +        """Proceed and cancel the statement, return Action.
> +
> +        This will delete the move.line and the reconciliation.
> +
> +        """
> +        return self.pool['account.bank.statement'].do_cancel(
> +            cr,
> +            uid,
> +            context['active_ids'],
> +            context=context
> +        )
> 
> === added file 'account_statement_cancel_line/wizard/cancel_statement_line.py'
> --- account_statement_cancel_line/wizard/cancel_statement_line.py	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/cancel_statement_line.py	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,46 @@
> +# -*- coding: utf-8 -*-
> +###############################################################################
> +#                                                                             #
> +#   Author: Leonardo Pistone
> +#   Copyright 2014 Camptocamp SA
> +#                                                                             #
> +#   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/>.     #
> +#                                                                             #
> +###############################################################################
> +"""Wizard to Cancel a Statement Line."""
> +
> +from openerp.osv import orm
> +
> +
> +class wizard_cancel_statement_line(orm.TransientModel):
> +
> +    """Wizard to Cancel a Statement Line."""
> +
> +    _name = "wizard.cancel.statement.line"
> +    _description = "Cancel Statement Line"
> +    _columns = {
> +    }
> +
> +    def unreconcile(self, cr, uid, ids, context=None):
> +        """Proceed and cancel the statement line, return Action.
> +
> +        This will delete the move.line and the reconciliation.
> +
> +        """
> +        return self.pool['account.bank.statement.line'].cancel(
> +            cr,
> +            uid,
> +            context['active_ids'],
> +            context=context
> +        )
> 
> === added file 'account_statement_cancel_line/wizard/cancel_statement_line_view.xml'
> --- account_statement_cancel_line/wizard/cancel_statement_line_view.xml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/cancel_statement_line_view.xml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,22 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<openerp>
> +    <data>
> +
> +        <record id="view_wizard_cancel_statement_line_form" model="ir.ui.view">
> +            <field name="name">view.wizard.cancel.statement.line.form</field>
> +            <field name="model">wizard.cancel.statement.line</field>
> +            <field name="arch" type="xml">
> +                <form string="Reconciled Entries" version="7.0">
> +                    <separator string="Unreconciliation"/>
> +                    <label string="Some entries are already reconciled. Do you want to unreconcile them and proceed?"/>
> +                    <footer>
> +                        <button name="unreconcile" string="Unreconcile" type="object" class="oe_highlight"/>
> +                        or
> +                        <button string="Cancel" class="oe_link" special="cancel"/>
> +                    </footer>
> +                </form>
> +            </field>
> +        </record>
> +
> +    </data>
> +</openerp>
> 
> === added file 'account_statement_cancel_line/wizard/cancel_statement_view.xml'
> --- account_statement_cancel_line/wizard/cancel_statement_view.xml	1970-01-01 00:00:00 +0000
> +++ account_statement_cancel_line/wizard/cancel_statement_view.xml	2014-06-13 10:06:12 +0000
> @@ -0,0 +1,24 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<openerp>
> +    <data>
> +
> +        <record id="view_wizard_cancel_statement_form" model="ir.ui.view">
> +            <field name="name">view.wizard.cancel.statement.form</field>
> +            <field name="model">wizard.cancel.statement</field>
> +            <field name="arch" type="xml">
> +                <form string="Reconciled Entries" version="7.0">
> +                    <separator string="Cancel statement"/>
> +                    <field name="reconcile_warning" invisible="1" />
> +                    <label attrs="{'invisible': [('reconcile_warning', '=', False)]}" string="Some entries are already reconciled. Do you want to unreconcile them and proceed?"/>
> +                    <label attrs="{'invisible': [('reconcile_warning', '=', True)]}" string="Cancelling the statement will delete the generated Journal Entries (if un posted) and could take a long time for a long statement. Do you want to proceed?"/>
> +                    <footer>
> +                        <button name="do_cancel_button" string="Proceed" type="object" class="oe_highlight"/>
> +                        or
> +                        <button string="Cancel" class="oe_link" special="cancel"/>
> +                    </footer>
> +                </form>
> +            </field>
> +        </record>
> +
> +    </data>
> +</openerp>
> 


-- 
https://code.launchpad.net/~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-cancel-line-lep/+merge/202831
Your team Banking Addons Core Editors is subscribed to branch lp:banking-addons/bank-statement-reconcile-7.0.


References