diff --git a/ir_sequence_standard_default/README.rst b/ir_sequence_standard_default/README.rst new file mode 100644 index 000000000..14948f4f0 --- /dev/null +++ b/ir_sequence_standard_default/README.rst @@ -0,0 +1,137 @@ +============================== +IrSequence Standard by Default +============================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/12.0/ir_sequence_standard_default + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-12-0/server-tools-12-0-ir_sequence_standard_default + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/149/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Set the implementation to "Standard" in all your current Sequences +(ir.sequence) and all new sequences are created as "Standard" by default +instead of "No Gap" implementation. + +What's the problem with "No Gap" Sequence Implementations +========================================================= + +"No Gap" is the default value of sequences in Odoo. However, this kind of +sequences cause more locks and can turn a database slow. + +Taking as example an invoice, if you assign an invoice number to one record, +but it sill not finish the process, this process must end in order to another +invoice could assign a new number and there was no gaps between the invoice +numbers. It seems to be good at first sight. But the problem starts when there +is a chained process. + +Imagine that there is one user that executes a process that produces 100 +invoices and these at the same time produces 100 journal entries that also use +a consecutive (no gap) sequence. And also those invoices are sent to sign with +and external institution (that could take 2 seconds in giving a response +because of internet latency or server load), and maybe they made another +calculations that makes them to take 5 seconds more for each invoice, and all +this is chained to one single transaction. This means that for 8.5 minutes +anybody else could confirm invoices, neither journal entries of the involved +journals. + +Now, think there is 20 users that have to execute a similar process. The +problem turns exponential. If another user comes to make an operation with the +same jornal it will thrown a concurrency failure. + +You can mitigate it if you segment each transaction and don't chain them. It +means, making commit for each invoice or process. It reduces the +probability that there is a concurrency error or a lock wait. However, it still +not solve it completely. + +Why to use Sequences with "Standard" Implementation +=================================================== + +If you use the standard sequence of PosgreSQL, it doesn't lock because at the +moment the request is done, the next sequence number it is changed in an +isolated transaction, and it have not to wait the other transaction to end. +However, if the transaction produces a rollback, this sequence isn't reverted, +it means, it's lost. It may be not not serious because when you cancel or +remove records that number is lost too. + +What this module does +===================== + +To eliminate completely that concurrency/slowness problem, this module changes +all the sequences (ir.sequence) implementation from "No Gap" to "Standard" with +the awareness that it will skip numbers. In the majority of database models +and many users projects there is no problem with that jump occurs. + +**Table of contents** + +.. contents:: + :local: + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Vauxoo + +Contributors +~~~~~~~~~~~~ + +- Moises López +- Erick Birbe + + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +.. |maintainer-moylop260| image:: https://github.com/moylop260.png?size=40px + :target: https://github.com/moylop260 + :alt: moylop260 +.. |maintainer-ebirbe| image:: https://github.com/ebirbe.png?size=40px + :target: https://github.com/ebirbe + :alt: ebirbe + +Current `maintainers `__: + +|maintainer-moylop260| |maintainer-ebirbe| + +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/ir_sequence_standard_default/__init__.py b/ir_sequence_standard_default/__init__.py new file mode 100644 index 000000000..bc2aac796 --- /dev/null +++ b/ir_sequence_standard_default/__init__.py @@ -0,0 +1,6 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import wizard +from . import tests diff --git a/ir_sequence_standard_default/__manifest__.py b/ir_sequence_standard_default/__manifest__.py new file mode 100644 index 000000000..ff232cb30 --- /dev/null +++ b/ir_sequence_standard_default/__manifest__.py @@ -0,0 +1,23 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +{ + 'name': 'IrSequence Standard by Default', + 'summary': 'Use Standard implementation of ir.sequence instead of NoGap', + 'version': '12.0.1.0.0', + 'author': 'Vauxoo, Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/server-tools', + 'maintainers': ['moylop260', 'ebirbe'], + 'license': 'AGPL-3', + 'category': 'Tools', + 'depends': [ + 'base_setup', + ], + 'data': [ + 'views/res_config_settings_views.xml', + 'wizard/sequence_standard_default_views.xml', + ], + 'installable': True, + 'application': False, +} diff --git a/ir_sequence_standard_default/models/__init__.py b/ir_sequence_standard_default/models/__init__.py new file mode 100644 index 000000000..0ae25614e --- /dev/null +++ b/ir_sequence_standard_default/models/__init__.py @@ -0,0 +1,4 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import res_config_settings diff --git a/ir_sequence_standard_default/models/res_config_settings.py b/ir_sequence_standard_default/models/res_config_settings.py new file mode 100644 index 000000000..5d3468189 --- /dev/null +++ b/ir_sequence_standard_default/models/res_config_settings.py @@ -0,0 +1,16 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ResConfigSettings(models.TransientModel): + + _inherit = "res.config.settings" + + @api.multi + def action_change_all_sequences(self): + self.ensure_one() + action = self.env.ref( + 'ir_sequence_standard_default.action_sequence_standard_default') + return action.read()[0] diff --git a/ir_sequence_standard_default/readme/CONTRIBUTORS.rst b/ir_sequence_standard_default/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..1ed71719b --- /dev/null +++ b/ir_sequence_standard_default/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +- Moises López +- Erick Birbe + diff --git a/ir_sequence_standard_default/readme/DESCRIPTION.rst b/ir_sequence_standard_default/readme/DESCRIPTION.rst new file mode 100644 index 000000000..8e87d8f65 --- /dev/null +++ b/ir_sequence_standard_default/readme/DESCRIPTION.rst @@ -0,0 +1,52 @@ +Set the implementation to "Standard" in all your current Sequences +(ir.sequence) and all new sequences are created as "Standard" by default +instead of "No Gap" implementation. + +What's the problem with "No Gap" Sequence Implementations +========================================================= + +"No Gap" is the default value of sequences in Odoo. However, this kind of +sequences cause more locks and can turn a database slow. + +Taking as example an invoice, if you assign an invoice number to one record, +but it sill not finish the process, this process must end in order to another +invoice could assign a new number and there was no gaps between the invoice +numbers. It seems to be good at first sight. But the problem starts when there +is a chained process. + +Imagine that there is one user that executes a process that produces 100 +invoices and these at the same time produces 100 journal entries that also use +a consecutive (no gap) sequence. And also those invoices are sent to sign with +and external institution (that could take 2 seconds in giving a response +because of internet latency or server load), and maybe they made another +calculations that makes them to take 5 seconds more for each invoice, and all +this is chained to one single transaction. This means that for 8.5 minutes +anybody else could confirm invoices, neither journal entries of the involved +journals. + +Now, think there is 20 users that have to execute a similar process. The +problem turns exponential. If another user comes to make an operation with the +same jornal it will thrown a concurrency failure. + +You can mitigate it if you segment each transaction and don't chain them. It +means, making commit for each invoice or process. It reduces the +probability that there is a concurrency error or a lock wait. However, it still +not solve it completely. + +Why to use Sequences with "Standard" Implementation +=================================================== + +If you use the standard sequence of PosgreSQL, it doesn't lock because at the +moment the request is done, the next sequence number it is changed in an +isolated transaction, and it have not to wait the other transaction to end. +However, if the transaction produces a rollback, this sequence isn't reverted, +it means, it's lost. It may be not not serious because when you cancel or +remove records that number is lost too. + +What this module does +===================== + +To eliminate completely that concurrency/slowness problem, this module changes +all the sequences (ir.sequence) implementation from "No Gap" to "Standard" with +the awareness that it will skip numbers. In the majority of database models +and many users projects there is no problem with that jump occurs. diff --git a/ir_sequence_standard_default/static/description/icon.png b/ir_sequence_standard_default/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/ir_sequence_standard_default/static/description/icon.png differ diff --git a/ir_sequence_standard_default/static/description/index.html b/ir_sequence_standard_default/static/description/index.html new file mode 100644 index 000000000..a5b322522 --- /dev/null +++ b/ir_sequence_standard_default/static/description/index.html @@ -0,0 +1,455 @@ + + + + + + +IrSequence Standard by Default + + + +
+

IrSequence Standard by Default

+ + +

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runbot

+

Set the implementation to “Standard” in all your current Sequences +(ir.sequence) and all new sequences are created as “Standard” by default +instead of “No Gap” implementation.

+
+

What’s the problem with “No Gap” Sequence Implementations

+

“No Gap” is the default value of sequences in Odoo. However, this kind of +sequences cause more locks and can turn a database slow.

+

Taking as example an invoice, if you assign an invoice number to one record, +but it sill not finish the process, this process must end in order to another +invoice could assign a new number and there was no gaps between the invoice +numbers. It seems to be good at first sight. But the problem starts when there +is a chained process.

+

Imagine that there is one user that executes a process that produces 100 +invoices and these at the same time produces 100 journal entries that also use +a consecutive (no gap) sequence. And also those invoices are sent to sign with +and external institution (that could take 2 seconds in giving a response +because of internet latency or server load), and maybe they made another +calculations that makes them to take 5 seconds more for each invoice, and all +this is chained to one single transaction. This means that for 8.5 minutes +anybody else could confirm invoices, neither journal entries of the involved +journals.

+

Now, think there is 20 users that have to execute a similar process. The +problem turns exponential. If another user comes to make an operation with the +same jornal it will thrown a concurrency failure.

+

You can mitigate it if you segment each transaction and don’t chain them. It +means, making commit for each invoice or process. It reduces the +probability that there is a concurrency error or a lock wait. However, it still +not solve it completely.

+
+
+

Why to use Sequences with “Standard” Implementation

+

If you use the standard sequence of PosgreSQL, it doesn’t lock because at the +moment the request is done, the next sequence number it is changed in an +isolated transaction, and it have not to wait the other transaction to end. +However, if the transaction produces a rollback, this sequence isn’t reverted, +it means, it’s lost. It may be not not serious because when you cancel or +remove records that number is lost too.

+
+
+

What this module does

+

To eliminate completely that concurrency/slowness problem, this module changes +all the sequences (ir.sequence) implementation from “No Gap” to “Standard” with +the awareness that it will skip numbers. In the majority of database models +and many users projects there is no problem with that jump occurs.

+

Table of contents

+
+
+

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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Vauxoo
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainers:

+

moylop260 ebirbe

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/ir_sequence_standard_default/tests/__init__.py b/ir_sequence_standard_default/tests/__init__.py new file mode 100644 index 000000000..34af958b9 --- /dev/null +++ b/ir_sequence_standard_default/tests/__init__.py @@ -0,0 +1,5 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_sequence_standard_default + diff --git a/ir_sequence_standard_default/tests/test_sequence_standard_default.py b/ir_sequence_standard_default/tests/test_sequence_standard_default.py new file mode 100644 index 000000000..eabdac345 --- /dev/null +++ b/ir_sequence_standard_default/tests/test_sequence_standard_default.py @@ -0,0 +1,46 @@ +# Copyright 2016 Vauxoo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestSequenceStandardDefault(TransactionCase): + + def setUp(self): + + super(TestSequenceStandardDefault, self).setUp() + self.wizard = self.env['sequence.standard.default'].create({}) + self.seq_nogap = self.env['ir.sequence'].create({ + 'name': 'NoGap Sequence', + 'implementation': 'no_gap', + 'use_date_range': False, + 'number_next_actual': 100, + }) + self.seq_nogap_range = self.env['ir.sequence'].create({ + 'name': 'NoGap Sequence with Date Range', + 'implementation': 'no_gap', + 'use_date_range': True, + }) + self.date_range = self.env['ir.sequence.date_range'].create({ + 'sequence_id': self.seq_nogap_range.id, + 'date_from': '2019-01-01', + 'date_to': '2019-12-31', + 'number_next_actual': 200, + }) + self.seq_standard = self.env['ir.sequence'].create({ + 'name': 'Standard Sequence', + 'implementation': 'standard', + 'number_next_actual': 300, + }) + + def test01_nogap_to_std(self): + self.wizard.execute() + + self.assertEqual(self.seq_nogap.implementation, 'standard') + self.assertEqual(self.seq_nogap.number_next_actual, 100) + + self.assertEqual(self.seq_nogap_range.implementation, 'standard') + self.assertEqual(self.date_range.number_next_actual, 200) + + self.assertEqual(self.seq_standard.implementation, 'standard') + self.assertEqual(self.seq_standard.number_next_actual, 300) diff --git a/ir_sequence_standard_default/views/res_config_settings_views.xml b/ir_sequence_standard_default/views/res_config_settings_views.xml new file mode 100644 index 000000000..469cd08f3 --- /dev/null +++ b/ir_sequence_standard_default/views/res_config_settings_views.xml @@ -0,0 +1,31 @@ + + + + + res.config.settings.view.form.inherit.sequence + res.config.settings + + + +
+

Sequences

+
+
+
+
+ Force Standard +
+ Change all your current No Gap sequences to Standard in order to improve performance. +
+
+
+
+
+
+
+ + + + + diff --git a/ir_sequence_standard_default/wizard/__init__.py b/ir_sequence_standard_default/wizard/__init__.py new file mode 100644 index 000000000..8f7dbbbbe --- /dev/null +++ b/ir_sequence_standard_default/wizard/__init__.py @@ -0,0 +1,4 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import sequence_standard_default diff --git a/ir_sequence_standard_default/wizard/sequence_standard_default.py b/ir_sequence_standard_default/wizard/sequence_standard_default.py new file mode 100644 index 000000000..18ce80e57 --- /dev/null +++ b/ir_sequence_standard_default/wizard/sequence_standard_default.py @@ -0,0 +1,42 @@ +# 2019 Vauxoo () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +from psycopg2.extensions import AsIs + +from odoo import api, models + +_logger = logging.getLogger(__name__) + + +class SequenceStandardDefault(models.TransientModel): + + _name = "sequence.standard.default" + _description = "Wizard to set all sequences to Standard implementation" + + @api.model + def change_all_sequences(self): + sequences = self.env['ir.sequence'].sudo().with_context( + active_test=False).search([('implementation', '=', 'no_gap')]) + _logger.info("Changing sequences to Standard: %s", sequences.ids) + for item in sequences: + seq_name = "ir_sequence_%03d" % (item.id) + self._cr.execute("DROP SEQUENCE IF EXISTS %s", [AsIs(seq_name), ]) + if item.use_date_range: + range_ids = {} + for line in item.date_range_ids: + range_ids[line.id] = line.number_next_actual + seq_name = "ir_sequence_%03d_%03d" % (item.id, line.id) + self._cr.execute( + "DROP SEQUENCE IF EXISTS %s", [AsIs(seq_name), ]) + item.write({'implementation': 'standard'}) + for line in item.date_range_ids: + line.write({'number_next_actual': range_ids[line.id]}) + continue + item.write({'implementation': 'standard'}) + + @api.multi + def execute(self): + self.ensure_one() + self.change_all_sequences() + return self.env.ref('base.ir_sequence_form').read()[0] diff --git a/ir_sequence_standard_default/wizard/sequence_standard_default_views.xml b/ir_sequence_standard_default/wizard/sequence_standard_default_views.xml new file mode 100644 index 000000000..670d456c0 --- /dev/null +++ b/ir_sequence_standard_default/wizard/sequence_standard_default_views.xml @@ -0,0 +1,32 @@ + + + + + Set All Sequences to Standard + sequence.standard.default + +
+

Warning:

+

All sequences in the system will be changed to the Standard + implementation of PostgreSQL. It will improve performance, + but sequence numbers may have gaps between each other.

+

What do you want to do?

+
+
+
+
+
+ + + Set All Sequences to Standard + ir.actions.act_window + sequence.standard.default + form + form + new + + +
+