Merge pull request #250 from acsone/8.0-account_default_draft_move-lga

account_default_draft_move forward port
This commit is contained in:
Stéphane Bidoul (ACSONE)
2015-09-04 14:04:21 +02:00
13 changed files with 356 additions and 63 deletions

View File

@@ -0,0 +1,122 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
==============================
Move in draft state by default
==============================
In Odoo there is a flag "Skip draft moves" on accounting journals that controls
if newly created account moves stay in draft state or are posted immediately.
This flag is honored throughout the system except for invoices and
bank statements, for which moves are posted as soon as the documents are
validated. Therefore, to correct errors on invoices and bank statement after
their validation, one is obliged to install the account_cancel module, which in turn
potentially enables the cancellation of all account moves. This is considered
dangerous by some.
To work around this issue, this module does the following:
* It makes sure the flag "Skip draft moves" is always honored, including when
validating invoices and bank statements [1]. This enables different workflows,
such as 1/ the automatic posting of moves coming from some journals (such as
invoices coming from e-commerce), or 2/ moves remaining in draft state, letting
accountants validate them and correct the corresponding invoices before posting
the moves.
* It hides the Cancel button on account moves unless account_cancel is installed
and cancellation is allowed on the corresponding journal.
* Additionnaly, the Post button is hidden on account moves, therefore providing
a framework where the user work with draft moves until everything is correct,
and validates all account moves at once and the end. [2]
[1] provided the parameter is set in Settings > Configuration, if this
parameter is not set the moves generated from invoices and bank statement
always remain in draft state ignoring the "Skip draft move flag" on
account journal. This parameter is not set by default for backward
compatibility with previous versions of account_default_draft_move.
[2] this behaviour will be made configurable in the near future.
Installation
============
To install this module, you need to:
* Click on install button
Configuration
=============
To configure this module, you need go to:
* Settings > Configuration > Accounting, and configure the checkbox
"Use journal setting to post journal entries on invoice and
bank statement validation" (if not checked, invoice and bank
statement move stay in draft state).
* On the sale/purchase and bank journals, configure the
"Skip draft move flag" to suit your needs.
Usage
=====
For further information, please visit:
* https://www.odoo.com/forum/help-1
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/92/8.0
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap
======================
* the visibility of the Post button on account moves should be made configurable
(this module currently hides it unconditionally)
* in 9.0, the parameter should be removed and always honoring the "Skip draft state"
flag should become the default
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20account_default_draft_move%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Vincent Renaville <vincent.renaville@camptocamp.com>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Joel Grand-Guillaume <joel.grandguillaume@camptocamp.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
* Matthieu Dietrich <matthieu.dietrich@camptocamp.com>
* Nicolas Bessi <nicolas.bessi@camptocamp.com>
* Adrien Peiffer <adrien.peiffer@acsone.eu>
* Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Rudolf Schnapka <rs@techno-flex.de>
* Laetitia Gangloff <laetitia.gangloff@acsone.eu>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@@ -19,3 +19,4 @@
##############################################################################
from . import account
from . import account_bank_statement
from . import res_config

View File

@@ -21,37 +21,15 @@
"name": "Move in draft state by default",
"version": "1.0",
"depends": ["base", "account", "account_constraints"],
"author": "Camptocamp,Odoo Community Association (OCA)",
"author": "Camptocamp,"
"ACSONE SA/NV,"
"Odoo Community Association (OCA)",
'license': 'AGPL-3',
"description": """
Let the generated move in draft on invoice and bank statement
validation. The main reason is to ease the user work day-to-day. At
first we used account_cancel, but this module allow to cancel posted
move and that's not allowed.
Two needs here:
- We want to be able to cancel an invoice (as soon as move are not
validated) without making a refund. Posted move can't be canceled.
- We want to ensure all move generated from bank statement and invoice
are generated in draft so we can still change them if needed.
Use this module with account_constraints (find it here:
https://launchpad.net/account-financial-tools or in
http://apps.openerp.com) and you'll get closely the same feature as
account_cancel, but with the insurance that user won't change posted
move.
The new framework will then be: always work with draft moves, allowing
people to change what they want. At the end of the period, validate all
moves. Till there, you ensure no-one can change something (or they'll
need to make a refund).
""",
'website': 'http://www.camptocamp.com',
'data': ['account_view.xml',
'invoice_view.xml'],
'invoice_view.xml',
'res_config_view.xml',
],
'installable': True,
'auto_install': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@@ -17,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
##############################################################################
from openerp import models, api, exceptions, _
from openerp import models, api, fields, exceptions, _
from openerp.tools.safe_eval import safe_eval
class AccountInvoice(models.Model):
@@ -27,8 +28,13 @@ class AccountInvoice(models.Model):
def action_move_create(self):
"""Set move line in draft state after creating them."""
res = super(AccountInvoice, self).action_move_create()
use_journal_setting = safe_eval(self.env['ir.config_parameter'].
get_param('use_journal_setting',
default="False"))
for inv in self:
if inv.move_id:
if use_journal_setting and inv.move_id.journal_id.entry_posted:
continue
inv.move_id.state = 'draft'
return res
@@ -55,3 +61,25 @@ class AccountMove(models.Model):
'SET state=%s '
'WHERE id IN %s', ('draft', tuple(self.ids)))
return True
@api.multi
def _is_update_posted(self):
ir_module = self.env['ir.module.module']
can_cancel = ir_module.search([('name', '=', 'account_cancel'),
('state', '=', 'installed')])
for move in self:
move.update_posted = can_cancel and move.journal_id.update_posted
update_posted = fields.Boolean(compute='_is_update_posted',
string='Allow Cancelling Entries')
class AccountJournal(models.Model):
_inherit = 'account.journal'
# update help of entry_posted flag
entry_posted = fields.Boolean(
string='Skip \'Draft\' State',
help="""Check this box if you don't want new journal entries
to pass through the 'draft' state and instead goes directly
to the 'posted state' without any manual validation.""")

View File

@@ -18,6 +18,7 @@
##############################################################################
from openerp import models, api
from openerp.tools.safe_eval import safe_eval
class AccountBankStatement(models.Model):
@@ -27,5 +28,14 @@ class AccountBankStatement(models.Model):
def button_confirm_bank(self):
res = super(AccountBankStatement, self).button_confirm_bank()
entries = self.mapped('line_ids.journal_entry_id')
use_journal_setting = safe_eval(self.env['ir.config_parameter'].
get_param('use_journal_setting',
default="False"))
if use_journal_setting:
new_entries = self.env['account.move']
for e in entries:
if not e.journal_id.entry_posted:
new_entries += e
entries = new_entries
entries.write({'state': 'draft'})
return res

View File

@@ -8,7 +8,12 @@
<field name="arch" type="xml">
<data>
<button name="button_validate" position="replace"/>
<button name="button_cancel" position="replace"/>
<button name="button_cancel" position="after">
<field name="update_posted" invisible="1"/>
</button>
<button name="button_cancel" position="attributes">
<attribute name="attrs">{'invisible': ['|', ('update_posted', '=', False)]}</attribute>
</button>
</data>
</field>
</record>

View File

@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-18 17:48+0000\n"
"PO-Revision-Date: 2013-10-18 17:48+0000\n"
"POT-Creation-Date: 2015-02-19 10:15+0000\n"
"PO-Revision-Date: 2015-02-19 10:15+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -31,7 +31,7 @@ msgid "Bank Statement"
msgstr ""
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:59
#, python-format
msgid "Error!"
msgstr ""
@@ -42,9 +42,19 @@ msgid "Invoice"
msgstr ""
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:60
#, python-format
msgid "You cannot modify a posted entry of this journal.\n"
"First you should set the journal to allow cancelling entries."
msgstr ""
#. module: account_default_draft_move
#: model:ir.model,name:account_default_draft_move.model_account_config_settings
msgid "account.config.settings"
msgstr ""
#. module: account_default_draft_move
#: field:account.config.settings,use_journal_setting:0
#: model:ir.model.fields,field_description:account_default_draft_move.field_account_config_settings_use_journal_setting
msgid "Use journal setting to post journal entries on invoice and bank statement validation"
msgstr ""

View File

@@ -33,7 +33,7 @@ msgid "Bank Statement"
msgstr "Bank Statement"
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:59
#, python-format
msgid "Error!"
msgstr ""
@@ -44,9 +44,20 @@ msgid "Invoice"
msgstr ""
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:60
#, python-format
msgid ""
"You cannot modify a posted entry of this journal.\n"
"First you should set the journal to allow cancelling entries."
msgstr ""
#. module: account_default_draft_move
#: model:ir.model,name:account_default_draft_move.model_account_config_settings
msgid "account.config.settings"
msgstr ""
#. module: account_default_draft_move
#: field:account.config.settings,use_journal_setting:0
#: model:ir.model.fields,field_description:account_default_draft_move.field_account_config_settings_use_journal_setting
msgid "Use journal setting to post journal entries on invoice and bank statement validation"
msgstr ""

View File

@@ -33,7 +33,7 @@ msgid "Bank Statement"
msgstr "Relevé bancaire"
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:59
#, python-format
msgid "Error!"
msgstr ""
@@ -44,9 +44,20 @@ msgid "Invoice"
msgstr "Facture"
#. module: account_default_draft_move
#: code:addons/account_default_draft_move/account.py:47
#: code:addons/account_default_draft_move/account.py:60
#, python-format
msgid ""
"You cannot modify a posted entry of this journal.\n"
"First you should set the journal to allow cancelling entries."
msgstr ""
#. module: account_default_draft_move
#: model:ir.model,name:account_default_draft_move.model_account_config_settings
msgid "account.config.settings"
msgstr ""
#. module: account_default_draft_move
#: field:account.config.settings,use_journal_setting:0
#: model:ir.model.fields,field_description:account_default_draft_move.field_account_config_settings_use_journal_setting
msgid "Use journal setting to post journal entries on invoice and bank statement validation"
msgstr "Utiliser les paramètres du journal pour comptabiliser les pièces comptables lièes aux factures et aux extraits bancaires"

View File

@@ -0,0 +1,55 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
#
# Copyright (c) 2014 ACSONE SA/NV (http://acsone.eu).
#
# 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/>.
#
##############################################################################
from openerp.osv import orm, fields
class AccountConfigSettings(orm.TransientModel):
_inherit = 'account.config.settings'
_columns = {
'use_journal_setting': fields.boolean(
'Use journal setting to post journal entries '
'on invoice and bank statement validation',),
}
def set_parameters(self, cr, uid, ids, context=None):
config = self.browse(cr, uid, ids[0], context)
config_pool = self.pool['ir.config_parameter']
if config.use_journal_setting:
config_pool.set_param(cr, uid, 'use_journal_setting',
config.use_journal_setting)
else:
# remove the key from parameter
ids = config_pool.search(cr, uid,
[('key', '=', 'use_journal_setting')],
context=context)
if ids:
config_pool.unlink(cr, uid, ids)
def default_get(self, cr, uid, fields, context=None):
res = super(AccountConfigSettings, self).default_get(cr, uid, fields,
context=context)
config_pool = self.pool['ir.config_parameter']
res['use_journal_setting'] = config_pool.get_param(
cr, uid, 'use_journal_setting', False)
return res

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_account_config_settings" model="ir.ui.view">
<field name="name">account.config.settings.inherit</field>
<field name="inherit_id" ref="account.view_account_config_settings"/>
<field name="model">account.config.settings</field>
<field name="arch" type="xml">
<div name="account_config" position="inside">
<div>
<field name="use_journal_setting" class="oe_inline"/>
<label for="use_journal_setting"/>
</div>
</div>
</field>
</record>
</data>
</openerp>

View File

@@ -1,16 +1,8 @@
# -*- coding: utf-8 -*-
#
##############################################################################
#
# Authors: Adrien Peiffer
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# All Rights Reserved
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs.
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contact a Free Software
# Service Company.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -25,6 +17,6 @@
# 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/>.
#
#
##############################################################################
from . import test_account_default_draft_move

View File

@@ -1,16 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# Authors: Adrien Peiffer
# Authors: Adrien Peiffer, Laetitia Gangloff
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# All Rights Reserved
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs.
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contact a Free Software
# Service Company.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -25,13 +17,15 @@
# 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/>.
#
#
##############################################################################
import openerp.tests.common as common
from datetime import datetime
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
from openerp import workflow
import time
def create_simple_invoice(self):
partner_id = self.ref('base.res_partner_2')
@@ -58,13 +52,69 @@ def create_simple_invoice(self):
})
def create_simple_bank_statement(self):
return self.env['account.bank.statement'].create({
'journal_id': self.ref("account.bank_journal"),
'date': time.strftime('%Y') + '-07-15',
'balance_end_real': 42,
'line_ids': [(0, 0, {'name': 'my payment',
'partner_id': self.ref('base.res_partner_2'),
'amount': 42,
'date': time.strftime('%Y') + '-07-15',
'account_id': self.ref('account.bnk')
})]
})
class TestAccountDefaultDraftMove(common.TransactionCase):
def setUp(self):
super(TestAccountDefaultDraftMove, self).setUp()
def test_draft_move_invoice(self):
invoice = create_simple_invoice(self)
workflow.trg_validate(self.uid, 'account.invoice', invoice.id,
'invoice_open', self.cr)
self.assertEqual(invoice.move_id.state, 'draft', 'State error!')
invoice = create_simple_invoice(self)
workflow.trg_validate(self.uid, 'account.invoice', invoice.id,
'invoice_open', self.cr)
self.assertEqual(invoice.move_id.state, 'draft', 'State error!')
def test_draft_move_statement(self):
statement = create_simple_bank_statement(self)
statement.button_confirm_bank()
self.assertEqual(statement.move_line_ids[0].move_id.state,
'draft', 'State error!')
def test_config_move_invoice(self):
# update configuration to take account of the journal settings
self.env['ir.config_parameter'].set_param('use_journal_setting', True)
# set entry posted to False
journal = self.env['account.journal'].browse(
self.ref('account.sales_journal'))
journal.entry_posted = False
invoice = create_simple_invoice(self)
workflow.trg_validate(self.uid, 'account.invoice', invoice.id,
'invoice_open', self.cr)
self.assertEqual(invoice.move_id.state, 'draft', 'State error!')
journal.entry_posted = True
invoice = create_simple_invoice(self)
workflow.trg_validate(self.uid, 'account.invoice', invoice.id,
'invoice_open', self.cr)
self.assertEqual(invoice.move_id.state, 'posted', 'State error!')
def test_config_move_statement(self):
# update configuration to take account of the journal settings
self.env['ir.config_parameter'].set_param('use_journal_setting', True)
# set entry posted to False
journal = self.env['account.journal'].browse(
self.ref('account.bank_journal'))
journal.entry_posted = False
statement = create_simple_bank_statement(self)
statement.button_confirm_bank()
self.assertEqual(statement.move_line_ids[0].move_id.state,
'draft', 'State error!')
journal.entry_posted = True
statement = create_simple_bank_statement(self)
statement.button_confirm_bank()
self.assertEqual(statement.move_line_ids[0].move_id.state,
'posted', 'State error!')