← Back to team overview

banking-addons-team team mailing list archive

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

 

Leonardo Pistone - camptocamp has proposed merging lp:~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-cancel-line-lep into lp:banking-addons/bank-statement-reconcile-7.0.

Commit message:
new module account_statement_cancel_line

Requested reviews:
  Banking Addons Core Editors (banking-addons-team)

For more details, see:
https://code.launchpad.net/~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-cancel-line-lep/+merge/202831

New module account_statement_cancel_line. See __openep__.py for a description of what that does.

Thanks!
-- 
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 requested to review the proposed merge of lp:~camptocamp/banking-addons/bank-statement-reconcile-7.0-add-cancel-line-lep into lp:banking-addons/bank-statement-reconcile-7.0.
=== 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-03-07 14:02:06 +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-03-07 14:02:06 +0000
@@ -0,0 +1,73 @@
+# -*- 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',
+    ],
+    '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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +0000
@@ -0,0 +1,104 @@
+# -*- 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):
+        """Change the state on the statement lines. Return super."""
+        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': 'confirmed'
+            }, context=context)
+
+        return super(Statement, self).button_confirm_bank(
+            cr, uid, ids, context)
+
+    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-03-07 14:02:06 +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')],
+            '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-03-07 14:02:06 +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-03-07 14:02:06 +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/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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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-03-07 14:02:06 +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>


Follow ups