From 2881b81a3f3ee39229be6e052c0132e2ab461316 Mon Sep 17 00:00:00 2001 From: gilles Date: Mon, 13 Mar 2017 14:18:36 +0100 Subject: [PATCH 1/5] [MIG] account_invoice_constraint_chronology --- .../README.rst | 58 +++++++ .../__init__.py | 29 ---- .../__manifest__.py | 59 ++------ .../model/__init__.py | 29 ---- .../model/account.py | 31 +--- .../model/account_invoice.py | 72 +++------ .../tests/__init__.py | 29 ---- .../test_account_constraint_chronology.py | 142 ++++++++---------- .../view/account_view.xml | 8 +- .../odoo/__init__.py | 1 + .../odoo/addons/__init__.py | 1 + .../account_invoice_constraint_chronology | 1 + .../setup.py | 6 + 13 files changed, 167 insertions(+), 299 deletions(-) create mode 100644 account_invoice_constraint_chronology/README.rst create mode 100644 setup/account_invoice_constraint_chronology/odoo/__init__.py create mode 100644 setup/account_invoice_constraint_chronology/odoo/addons/__init__.py create mode 120000 setup/account_invoice_constraint_chronology/odoo/addons/account_invoice_constraint_chronology create mode 100644 setup/account_invoice_constraint_chronology/setup.py diff --git a/account_invoice_constraint_chronology/README.rst b/account_invoice_constraint_chronology/README.rst new file mode 100644 index 000000000..7ff9af8ec --- /dev/null +++ b/account_invoice_constraint_chronology/README.rst @@ -0,0 +1,58 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +===================================== +Account Invoice Constraint Chronology +===================================== + +This module helps ensuring the chronology of invoice numbers. + +It prevents the validation of invoices when: + +* there are draft invoices with an anterior date +* there are validated invoices with a posterior date + +Configuration +============= + +To configure this module, go to the menu *Accounting > Configuration > Journals > Journals* and activate the option *Check Chronology* on the relevant journals. After the installation of the module, this option will be active on *sale* and *sale refund* journals. + +Usage +===== + +.. 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 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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. + +Credits +======= + +Contributors +------------ + +* Adrien Peiffer (`Acsone SA/NV `_) +* Gilles Gilles + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/account_invoice_constraint_chronology/__init__.py b/account_invoice_constraint_chronology/__init__.py index dcf937772..d6af31449 100644 --- a/account_invoice_constraint_chronology/__init__.py +++ b/account_invoice_constraint_chronology/__init__.py @@ -1,31 +1,2 @@ -# -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# - from . import model from . import tests diff --git a/account_invoice_constraint_chronology/__manifest__.py b/account_invoice_constraint_chronology/__manifest__.py index c6d311634..2a334a8a6 100644 --- a/account_invoice_constraint_chronology/__manifest__.py +++ b/account_invoice_constraint_chronology/__manifest__.py @@ -1,60 +1,23 @@ # -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# - +# Copyright 2015-2017 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Account Invoice Constraint Chronology", - "version": "8.0.1.0.0", + "version": "10.0.1.0.0", "author": "ACSONE SA/NV,Odoo Community Association (OCA)", "maintainer": "ACSONE SA/NV", "website": "http://www.acsone.eu", "license": "AGPL-3", - "images": [], "category": "Accounting", "depends": ["account"], "description": """ -Account Invoice Constraint Chronology -===================================== - -This module helps ensuring the chronology of invoice numbers. - -It prevents the validation of invoices when: -* there are draft invoices with an anterior date -* there are validated invoices with a posterior date - -The check can be activated on a per-journal basis -(for sale and purchase journals). -""", + Account Invoice Constraint Chronology + This module helps ensuring the chronology of invoice numbers. + It prevents the validation of invoices when: + * there are draft invoices with an anterior date + * there are validated invoices with a posterior date + """, + "test": ["../account/test/account_minimal_test.xml"], "data": ["view/account_view.xml"], - "demo": [], - "test": [], - "licence": "AGPL-3", - 'installable': False, - "auto_install": False, - "application": True, + 'installable': True, } diff --git a/account_invoice_constraint_chronology/model/__init__.py b/account_invoice_constraint_chronology/model/__init__.py index d01496542..97b1db6fd 100644 --- a/account_invoice_constraint_chronology/model/__init__.py +++ b/account_invoice_constraint_chronology/model/__init__.py @@ -1,31 +1,2 @@ -# -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# - from . import account_invoice from . import account diff --git a/account_invoice_constraint_chronology/model/account.py b/account_invoice_constraint_chronology/model/account.py index 9a7d36337..3cf04a463 100644 --- a/account_invoice_constraint_chronology/model/account.py +++ b/account_invoice_constraint_chronology/model/account.py @@ -1,33 +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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# +# Copyright 2015-2017 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import models, fields, api +from odoo import models, fields, api class account_journal(models.Model): diff --git a/account_invoice_constraint_chronology/model/account_invoice.py b/account_invoice_constraint_chronology/model/account_invoice.py index c9ac805f5..4dd19daf3 100644 --- a/account_invoice_constraint_chronology/model/account_invoice.py +++ b/account_invoice_constraint_chronology/model/account_invoice.py @@ -1,42 +1,16 @@ # -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# +# Copyright 2015-2017 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import models, api, fields -from openerp.tools.translate import _ -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -from datetime import datetime -from openerp import exceptions +from odoo import models, api, fields, _ +from odoo.exceptions import UserError class account_invoice(models.Model): _inherit = "account.invoice" + already_validated = fields.Boolean(readonly=True, copy=False) + @api.multi def action_move_create(self): res = super(account_invoice, self).action_move_create() @@ -51,33 +25,31 @@ class account_invoice(models.Model): ('journal_id', '=', inv.journal_id.id)], limit=1) if len(invoices) > 0: - date_invoice_format = datetime\ - .strptime(inv.date_invoice, - DEFAULT_SERVER_DATE_FORMAT) + date_invoice_format = fields.Date.\ + from_string(inv.date_invoice) date_invoice_tz = fields\ .Date.context_today(self, date_invoice_format) - raise exceptions.Warning(_("Chronology Error." - " Please confirm older draft" - " invoices before %s and" - " try again.") % - date_invoice_tz) - - if inv.internal_number is False: + raise UserError(_("Chronology Error. " + "Please confirm older draft " + "invoices before %s and try again.") + % date_invoice_tz) + if not inv.already_validated: invoices = self.search([('state', 'in', ['open', 'paid']), ('date_invoice', '>', inv.date_invoice), ('journal_id', '=', inv.journal_id.id)], limit=1) + if len(invoices) > 0: - date_invoice_format = datetime\ - .strptime(inv.date_invoice, - DEFAULT_SERVER_DATE_FORMAT) + date_invoice_format = fields.Date.\ + from_string(inv.date_invoice) date_invoice_tz = fields\ .Date.context_today(self, date_invoice_format) - raise exceptions.Warning(_("Chronology Error. There" - " exist at least one" - " invoice with a date" - " posterior to %s.") % - date_invoice_tz) + raise UserError(_("Chronology Error. " + "There exist at least one invoice " + "with a date posterior to %s.") % + date_invoice_tz) + if not inv.already_validated: + inv.already_validated = True return res diff --git a/account_invoice_constraint_chronology/tests/__init__.py b/account_invoice_constraint_chronology/tests/__init__.py index 3dd2ee2c0..1f3c5398d 100644 --- a/account_invoice_constraint_chronology/tests/__init__.py +++ b/account_invoice_constraint_chronology/tests/__init__.py @@ -1,30 +1 @@ -# -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# - from . import test_account_constraint_chronology diff --git a/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py b/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py index df5a2ed7a..1781f6968 100644 --- a/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py +++ b/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py @@ -1,90 +1,62 @@ # -*- 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 -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# +# Copyright 2015-2017 ACSONE SA/NV () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import openerp.tests.common as common -from openerp import workflow -from openerp import exceptions +import odoo.tests.common as common +from odoo.exceptions import UserError from datetime import datetime, timedelta -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT - - -def get_simple_product_id(self): - return self.env['product.product'].create({'name': 'product_test_01', - 'lst_price': 2000.00, - }) +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT def get_journal_check(self, value): - sale_journal_id = self.ref('account.sales_journal') - sale_journal = self.env['account.journal'].browse([sale_journal_id]) - journal = sale_journal.copy() + sale_journal_obj = self.AccountJournal.env['account.journal'].\ + search([('type', '=', 'sale')], limit=1) + journal = sale_journal_obj.copy() journal.check_chronology = value return journal -def get_simple_account_invoice_line_values(self, product_id): - return {'name': 'test', - 'account_id': self.ref('account.a_sale'), - 'price_unit': 2000.00, - 'quantity': 1, - 'product_id': product_id, - } - - def create_simple_invoice(self, journal_id, date): - partner_id = self.ref('base.res_partner_2') - product = get_simple_product_id(self) - return self.env['account.invoice']\ - .create({'partner_id': partner_id, - 'account_id': - self.ref('account.a_recv'), - 'journal_id': - journal_id, - 'date_invoice': date, - 'invoice_line': [(0, 0, {'name': 'test', - 'account_id': - self.ref('account.a_sale'), - 'price_unit': 2000.00, - 'quantity': 1, - 'product_id': product.id, - } - ) - ], - }) + invoice_account = self.env['account.account'].\ + search([('user_type_id', '=', + self.env.ref( + 'account.data_account_type_receivable' + ).id)], limit=1).id + invoice_line_account = self.env['account.account'].\ + search([('user_type_id', '=', + self.env.ref( + 'account.data_account_type_expenses' + ).id)], limit=1).id + analytic_account = self.env['account.analytic.account'].\ + create({'name': 'test account'}) + + invoice = self.env['account.invoice'].create( + {'partner_id': self.env.ref('base.res_partner_2').id, + 'account_id': invoice_account, + 'type': 'in_invoice', + 'journal_id': journal_id, + 'date_invoice': date, + 'state': 'draft', + }) + # invoice.write({'internal_number': invoice.number}) + self.env['account.invoice.line'].create( + {'product_id': self.env.ref('product.product_product_4').id, + 'quantity': 1.0, + 'price_unit': 100.0, + 'invoice_id': invoice.id, + 'name': 'product that cost 100', + 'account_id': invoice_line_account, + 'account_analytic_id': analytic_account.id, + }) + return invoice class TestAccountConstraintChronology(common.TransactionCase): def setUp(self): super(TestAccountConstraintChronology, self).setUp() - self.context = self.registry("res.users").context_get(self.cr, - self.uid) + self.AccountJournal = self.env['account.journal'] + self.Account = self.env['account.account'] def test_invoice_draft(self): journal = get_journal_check(self, True) @@ -94,23 +66,26 @@ class TestAccountConstraintChronology(common.TransactionCase): create_simple_invoice(self, journal.id, date) date = today.strftime(DEFAULT_SERVER_DATE_FORMAT) invoice_2 = create_simple_invoice(self, journal.id, date) - self.assertRaises(exceptions.Warning, workflow.trg_validate, self.uid, - 'account.invoice', invoice_2.id, 'invoice_open', - self.cr) + self.assertTrue((invoice_2.state == 'draft'), + "Initial invoice state is not Draft") + with self.assertRaises(UserError): + invoice_2.action_invoice_open() def test_invoice_validate(self): journal = get_journal_check(self, True) today = datetime.now() tomorrow = today + timedelta(days=1) - date = tomorrow.strftime(DEFAULT_SERVER_DATE_FORMAT) - invoice = create_simple_invoice(self, journal.id, date) - workflow.trg_validate(self.uid, 'account.invoice', invoice.id, - 'invoice_open', self.cr) + date_tomorrow = tomorrow.strftime(DEFAULT_SERVER_DATE_FORMAT) + invoice_1 = create_simple_invoice(self, journal.id, date_tomorrow) + self.assertTrue((invoice_1.state == 'draft'), + "Initial invoice state is not Draft") + invoice_1.action_invoice_open() date = today.strftime(DEFAULT_SERVER_DATE_FORMAT) invoice_2 = create_simple_invoice(self, journal.id, date) - self.assertRaises(exceptions.Warning, workflow.trg_validate, self.uid, - 'account.invoice', invoice_2.id, 'invoice_open', - self.cr) + self.assertTrue((invoice_2.state == 'draft'), + "Initial invoice state is not Draft") + with self.assertRaises(UserError): + invoice_2.action_invoice_open() def test_invoice_without_date(self): journal = get_journal_check(self, True) @@ -119,6 +94,7 @@ class TestAccountConstraintChronology(common.TransactionCase): date = yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT) create_simple_invoice(self, journal.id, date) invoice_2 = create_simple_invoice(self, journal.id, False) - self.assertRaises(exceptions.Warning, workflow.trg_validate, self.uid, - 'account.invoice', invoice_2.id, 'invoice_open', - self.cr) + self.assertTrue((invoice_2.state == 'draft'), + "Initial invoice state is not Draft") + with self.assertRaises(UserError): + invoice_2.action_invoice_open() diff --git a/account_invoice_constraint_chronology/view/account_view.xml b/account_invoice_constraint_chronology/view/account_view.xml index 1fc86dfe7..95baf1ee0 100644 --- a/account_invoice_constraint_chronology/view/account_view.xml +++ b/account_invoice_constraint_chronology/view/account_view.xml @@ -1,15 +1,17 @@ - + + account.journal.form (account_constraint_chronology) account.journal - + - + diff --git a/setup/account_invoice_constraint_chronology/odoo/__init__.py b/setup/account_invoice_constraint_chronology/odoo/__init__.py new file mode 100644 index 000000000..de40ea7ca --- /dev/null +++ b/setup/account_invoice_constraint_chronology/odoo/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/setup/account_invoice_constraint_chronology/odoo/addons/__init__.py b/setup/account_invoice_constraint_chronology/odoo/addons/__init__.py new file mode 100644 index 000000000..de40ea7ca --- /dev/null +++ b/setup/account_invoice_constraint_chronology/odoo/addons/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/setup/account_invoice_constraint_chronology/odoo/addons/account_invoice_constraint_chronology b/setup/account_invoice_constraint_chronology/odoo/addons/account_invoice_constraint_chronology new file mode 120000 index 000000000..7803a30bb --- /dev/null +++ b/setup/account_invoice_constraint_chronology/odoo/addons/account_invoice_constraint_chronology @@ -0,0 +1 @@ +../../../../account_invoice_constraint_chronology \ No newline at end of file diff --git a/setup/account_invoice_constraint_chronology/setup.py b/setup/account_invoice_constraint_chronology/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/account_invoice_constraint_chronology/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 389874cdc2ae44ade2d67869d131e911b24f52b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Tue, 14 Mar 2017 17:26:24 +0100 Subject: [PATCH 2/5] [IMP] a_i_c_chronology: better check for previously validated invoices --- .../model/account_invoice.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/account_invoice_constraint_chronology/model/account_invoice.py b/account_invoice_constraint_chronology/model/account_invoice.py index 4dd19daf3..b93e14af4 100644 --- a/account_invoice_constraint_chronology/model/account_invoice.py +++ b/account_invoice_constraint_chronology/model/account_invoice.py @@ -9,10 +9,9 @@ from odoo.exceptions import UserError class account_invoice(models.Model): _inherit = "account.invoice" - already_validated = fields.Boolean(readonly=True, copy=False) - @api.multi def action_move_create(self): + previously_validated = self.filtered(lambda inv: inv.move_name) res = super(account_invoice, self).action_move_create() for inv in self: if inv.journal_id.check_chronology: @@ -33,7 +32,7 @@ class account_invoice(models.Model): "Please confirm older draft " "invoices before %s and try again.") % date_invoice_tz) - if not inv.already_validated: + if inv not in previously_validated: invoices = self.search([('state', 'in', ['open', 'paid']), ('date_invoice', '>', inv.date_invoice), @@ -50,6 +49,4 @@ class account_invoice(models.Model): "There exist at least one invoice " "with a date posterior to %s.") % date_invoice_tz) - if not inv.already_validated: - inv.already_validated = True return res From 664b5233fdcfa19a689f40443a5854c1ce906a64 Mon Sep 17 00:00:00 2001 From: gilles Date: Tue, 14 Mar 2017 19:09:03 +0100 Subject: [PATCH 3/5] [FIX] cleanup --- .../README.rst | 2 +- .../__manifest__.py | 8 -- .../model/account.py | 12 +- .../model/account_invoice.py | 4 +- .../test_account_constraint_chronology.py | 123 ++++++++++-------- .../view/account_view.xml | 22 ++-- 6 files changed, 88 insertions(+), 83 deletions(-) diff --git a/account_invoice_constraint_chronology/README.rst b/account_invoice_constraint_chronology/README.rst index 7ff9af8ec..78fad5acc 100644 --- a/account_invoice_constraint_chronology/README.rst +++ b/account_invoice_constraint_chronology/README.rst @@ -23,7 +23,7 @@ Usage .. 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 + :target: https://runbot.odoo-community.org/runbot/92/10.0 Bug Tracker =========== diff --git a/account_invoice_constraint_chronology/__manifest__.py b/account_invoice_constraint_chronology/__manifest__.py index 2a334a8a6..ebed7b86c 100644 --- a/account_invoice_constraint_chronology/__manifest__.py +++ b/account_invoice_constraint_chronology/__manifest__.py @@ -10,14 +10,6 @@ "license": "AGPL-3", "category": "Accounting", "depends": ["account"], - "description": """ - Account Invoice Constraint Chronology - This module helps ensuring the chronology of invoice numbers. - It prevents the validation of invoices when: - * there are draft invoices with an anterior date - * there are validated invoices with a posterior date - """, - "test": ["../account/test/account_minimal_test.xml"], "data": ["view/account_view.xml"], 'installable': True, } diff --git a/account_invoice_constraint_chronology/model/account.py b/account_invoice_constraint_chronology/model/account.py index 3cf04a463..04bbbd186 100644 --- a/account_invoice_constraint_chronology/model/account.py +++ b/account_invoice_constraint_chronology/model/account.py @@ -5,15 +5,15 @@ from odoo import models, fields, api -class account_journal(models.Model): +class AccountJournal(models.Model): _inherit = ['account.journal'] check_chronology = fields.Boolean(string='Check Chronology', default=False) - @api.one + @api.multi @api.onchange('type') def on_change_type(self): - if self.type not in ['sale', 'purchase', 'sale_refund', - 'purchase_refund']: - self.check_chronology = False - return True + for rec in self: + if rec.type not in ['sale', 'purchase']: + rec.check_chronology = False + return True diff --git a/account_invoice_constraint_chronology/model/account_invoice.py b/account_invoice_constraint_chronology/model/account_invoice.py index b93e14af4..b7bc0fd1f 100644 --- a/account_invoice_constraint_chronology/model/account_invoice.py +++ b/account_invoice_constraint_chronology/model/account_invoice.py @@ -6,13 +6,13 @@ from odoo import models, api, fields, _ from odoo.exceptions import UserError -class account_invoice(models.Model): +class AccountInvoice(models.Model): _inherit = "account.invoice" @api.multi def action_move_create(self): previously_validated = self.filtered(lambda inv: inv.move_name) - res = super(account_invoice, self).action_move_create() + res = super(AccountInvoice, self).action_move_create() for inv in self: if inv.journal_id.check_chronology: invoices = \ diff --git a/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py b/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py index 1781f6968..9a88bbacb 100644 --- a/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py +++ b/account_invoice_constraint_chronology/tests/test_account_constraint_chronology.py @@ -8,92 +8,107 @@ from datetime import datetime, timedelta from odoo.tools import DEFAULT_SERVER_DATE_FORMAT -def get_journal_check(self, value): - sale_journal_obj = self.AccountJournal.env['account.journal'].\ - search([('type', '=', 'sale')], limit=1) - journal = sale_journal_obj.copy() - journal.check_chronology = value - return journal - - -def create_simple_invoice(self, journal_id, date): - invoice_account = self.env['account.account'].\ - search([('user_type_id', '=', - self.env.ref( - 'account.data_account_type_receivable' - ).id)], limit=1).id - invoice_line_account = self.env['account.account'].\ - search([('user_type_id', '=', - self.env.ref( - 'account.data_account_type_expenses' - ).id)], limit=1).id - analytic_account = self.env['account.analytic.account'].\ - create({'name': 'test account'}) - - invoice = self.env['account.invoice'].create( - {'partner_id': self.env.ref('base.res_partner_2').id, - 'account_id': invoice_account, - 'type': 'in_invoice', - 'journal_id': journal_id, - 'date_invoice': date, - 'state': 'draft', - }) - # invoice.write({'internal_number': invoice.number}) - self.env['account.invoice.line'].create( - {'product_id': self.env.ref('product.product_product_4').id, - 'quantity': 1.0, - 'price_unit': 100.0, - 'invoice_id': invoice.id, - 'name': 'product that cost 100', - 'account_id': invoice_line_account, - 'account_analytic_id': analytic_account.id, - }) - return invoice - - class TestAccountConstraintChronology(common.TransactionCase): def setUp(self): super(TestAccountConstraintChronology, self).setUp() - self.AccountJournal = self.env['account.journal'] - self.Account = self.env['account.account'] + + # Needed to create invoice + + self.account_type1 = self.env['account.account.type'].\ + create({'name': 'acc type test 1', + 'type': 'receivable', + 'include_initial_balance': True}) + self.account_type2 = self.env['account.account.type']. \ + create({'name': 'acc type test 2', + 'type': 'other', + 'include_initial_balance': True}) + self.account_account = self.env['account.account'].\ + create({'name': 'acc test', + 'code': 'X2020', + 'user_type_id': self.account_type1.id, + 'reconcile': True}) + self.account_account_line = self.env['account.account']. \ + create({'name': 'acc inv line test', + 'code': 'X2021', + 'user_type_id': self.account_type2.id, + 'reconcile': True}) + self.sequence = self.env['ir.sequence'].create( + {'name': 'Journal Sale', + 'prefix': 'SALE', 'padding': 6, + 'company_id': self.env.ref("base.main_company").id}) + self.account_journal_sale = self.env['account.journal']\ + .create({'name': 'Sale journal', + 'code': 'SALE', + 'type': 'sale', + 'sequence_id': self.sequence.id}) + self.product = self.env['product.product'].create( + {'name': 'product name'}) + self.analytic_account = self.env['account.analytic.account'].\ + create({'name': 'test account'}) + + def get_journal_check(self, value): + journal = self.account_journal_sale.copy() + journal.check_chronology = value + return journal + + def create_simple_invoice(self, journal_id, date): + invoice = self.env['account.invoice'].create( + {'partner_id': self.env.ref('base.res_partner_2').id, + 'account_id': self.account_account.id, + 'type': 'in_invoice', + 'journal_id': journal_id, + 'date_invoice': date, + 'state': 'draft', + }) + + self.env['account.invoice.line'].create( + {'product_id': self.product.id, + 'quantity': 1.0, + 'price_unit': 100.0, + 'invoice_id': invoice.id, + 'name': 'product that cost 100', + 'account_id': self.account_account_line.id, + 'account_analytic_id': self.analytic_account.id, + }) + return invoice def test_invoice_draft(self): - journal = get_journal_check(self, True) + journal = self.get_journal_check(True) today = datetime.now() yesterday = today - timedelta(days=1) date = yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT) - create_simple_invoice(self, journal.id, date) + self.create_simple_invoice(journal.id, date) date = today.strftime(DEFAULT_SERVER_DATE_FORMAT) - invoice_2 = create_simple_invoice(self, journal.id, date) + invoice_2 = self.create_simple_invoice(journal.id, date) self.assertTrue((invoice_2.state == 'draft'), "Initial invoice state is not Draft") with self.assertRaises(UserError): invoice_2.action_invoice_open() def test_invoice_validate(self): - journal = get_journal_check(self, True) + journal = self.get_journal_check(True) today = datetime.now() tomorrow = today + timedelta(days=1) date_tomorrow = tomorrow.strftime(DEFAULT_SERVER_DATE_FORMAT) - invoice_1 = create_simple_invoice(self, journal.id, date_tomorrow) + invoice_1 = self.create_simple_invoice(journal.id, date_tomorrow) self.assertTrue((invoice_1.state == 'draft'), "Initial invoice state is not Draft") invoice_1.action_invoice_open() date = today.strftime(DEFAULT_SERVER_DATE_FORMAT) - invoice_2 = create_simple_invoice(self, journal.id, date) + invoice_2 = self.create_simple_invoice(journal.id, date) self.assertTrue((invoice_2.state == 'draft'), "Initial invoice state is not Draft") with self.assertRaises(UserError): invoice_2.action_invoice_open() def test_invoice_without_date(self): - journal = get_journal_check(self, True) + journal = self.get_journal_check(True) today = datetime.now() yesterday = today - timedelta(days=1) date = yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT) - create_simple_invoice(self, journal.id, date) - invoice_2 = create_simple_invoice(self, journal.id, False) + self.create_simple_invoice(journal.id, date) + invoice_2 = self.create_simple_invoice(journal.id, False) self.assertTrue((invoice_2.state == 'draft'), "Initial invoice state is not Draft") with self.assertRaises(UserError): diff --git a/account_invoice_constraint_chronology/view/account_view.xml b/account_invoice_constraint_chronology/view/account_view.xml index 95baf1ee0..20a236ea6 100644 --- a/account_invoice_constraint_chronology/view/account_view.xml +++ b/account_invoice_constraint_chronology/view/account_view.xml @@ -2,16 +2,14 @@ - - - account.journal.form (account_constraint_chronology) - account.journal - - - - - - - - + + account.journal.form (account_constraint_chronology) + account.journal + + + + + + + From 24f90e95283de089962247d72563f0e74e0f6a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Mon, 29 May 2017 13:21:20 +0200 Subject: [PATCH 4/5] [IMP] a_i_c_chronology: improve/fox onchange --- account_invoice_constraint_chronology/model/account.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/account_invoice_constraint_chronology/model/account.py b/account_invoice_constraint_chronology/model/account.py index 04bbbd186..81884b497 100644 --- a/account_invoice_constraint_chronology/model/account.py +++ b/account_invoice_constraint_chronology/model/account.py @@ -10,10 +10,7 @@ class AccountJournal(models.Model): check_chronology = fields.Boolean(string='Check Chronology', default=False) - @api.multi @api.onchange('type') - def on_change_type(self): - for rec in self: - if rec.type not in ['sale', 'purchase']: - rec.check_chronology = False - return True + def _onchange_type(self): + if self.type not in ['sale', 'purchase']: + self.check_chronology = False From 067c85e1d6168dfcaa4372bf2d8d8b45c6cef838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Mon, 29 May 2017 14:47:31 +0200 Subject: [PATCH 5/5] [IMP] a_i_c_chronology: simplify if statements --- .../model/account_invoice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/account_invoice_constraint_chronology/model/account_invoice.py b/account_invoice_constraint_chronology/model/account_invoice.py index b7bc0fd1f..08af1b78d 100644 --- a/account_invoice_constraint_chronology/model/account_invoice.py +++ b/account_invoice_constraint_chronology/model/account_invoice.py @@ -23,7 +23,7 @@ class AccountInvoice(models.Model): ('date_invoice', '<', inv.date_invoice), ('journal_id', '=', inv.journal_id.id)], limit=1) - if len(invoices) > 0: + if invoices: date_invoice_format = fields.Date.\ from_string(inv.date_invoice) date_invoice_tz = fields\ @@ -40,7 +40,7 @@ class AccountInvoice(models.Model): inv.journal_id.id)], limit=1) - if len(invoices) > 0: + if invoices: date_invoice_format = fields.Date.\ from_string(inv.date_invoice) date_invoice_tz = fields\