diff --git a/__manifest__.py b/__manifest__.py
index eb51915aa96469343c266e9deb43f88f2dbe1d76..7fcc52ee63a6be8d80473efa1279ca24192455ac 100755
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -11,12 +11,14 @@
         "l10n_fr",
         "lefilament_export_journal_tool",
         "cgscop_cotisation",
+        "queue_job_batch",
     ],
     "data": [
         # Security
         "security/security_rules.xml",
         "security/ir.model.access.csv",
         "datas/mail_data.xml",
+        "datas/queue_job_data.xml",
         "datas/ir_sequence_data.xml",
         # Reports
         "report/report_scop_bordereau.xml",
diff --git a/datas/queue_job_data.xml b/datas/queue_job_data.xml
new file mode 100644
index 0000000000000000000000000000000000000000..01f22859e7e811dfc5d607083dc3a157edc9db19
--- /dev/null
+++ b/datas/queue_job_data.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- Copyright 2021 Le Filament (<https://www.le-filament.com>)
+     License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). -->
+<odoo>
+    <data noupdate="1">
+
+        <record id="job_function_cotisation_cg_create_bordereau" model="queue.job.function">
+            <field name="model_id" ref="cgscop_cotisation_cg.model_scop_cotisation_cg" />
+            <field name="method">create_bordereau</field>
+            <field name="channel_id" ref="queue_job.channel_root" />
+            <field name="related_action" eval='{"func_name": "related_action_custom", "kwargs": {"model": "scop.bordereau", "record": "result"}}' />
+            <field name="retry_pattern" eval="{1: 10, 5: 30, 10: 300}" />
+        </record>
+
+        <record id="job_function_cotisation_cg_validate_bordereau" model="queue.job.function">
+            <field name="model_id" ref="cgscop_cotisation_cg.model_scop_bordereau" />
+            <field name="method">validate_bordereau</field>
+            <field name="channel_id" ref="queue_job.channel_root" />
+            <field name="related_action" eval='{"func_name": "related_action_custom", "kwargs": {"record": "result"}}' />
+            <field name="retry_pattern" eval="{1: 10, 5: 30, 10: 300}" />
+        </record>
+
+    </data>
+</odoo>
\ No newline at end of file
diff --git a/models/scop_bordereau_cg.py b/models/scop_bordereau_cg.py
index cd0960f3dca21fce41cce7c3b4330ebc2133c407..ec3728614fc2b2b3cb6992dabfd8ab8675a531d7 100644
--- a/models/scop_bordereau_cg.py
+++ b/models/scop_bordereau_cg.py
@@ -382,16 +382,28 @@ class Bordereau(models.Model):
                     inv.action_invoice_open()
 
     def validate_bordereau(self):
+        """
+        Affecte le nom du bordereau avec la séquence et valide les invoices
+        """
         self.ensure_one()
         if self.name == 'Brouillon':
             self.name = self.env['ir.sequence'].next_by_code('scop.bordereau')
         self.validate_cotiz_cg()
+        return self.id
 
     @api.multi
     def validate_bordereau_multi(self):
-        threaded_validate_bordereau = threading.Thread(
-            target=self.process_bordereau_validate)
-        threaded_validate_bordereau.start()
+        """
+        Utilise job queue pour valider les bordereaux
+        """
+        batch_name = (fields.Datetime.to_string(fields.Datetime.now()) +
+                      " Validation bordereaux ")
+        batch = self.env['queue.job.batch'].get_new_batch(batch_name)
+        for bordereau in self:
+            bordereau.with_context(
+                job_batch=batch
+            ).with_delay().validate_bordereau()
+        batch.enqueue()
 
     @api.multi
     def print_bordereau(self):
@@ -472,6 +484,9 @@ class Bordereau(models.Model):
         return action
 
     def action_show_cotiz(self):
+        """
+        :return: Ouvre la vue des cotisations liées au bordereau
+        """
         tree_view_id = self.env.ref(
             'cgscop_cotisation.invoice_tree_scop_inherited').id
         form_view_id = self.env.ref(
@@ -490,6 +505,9 @@ class Bordereau(models.Model):
         }
 
     def action_change_liasse(self):
+        """
+        :return: Ouvre le wizard pour changer la liasse
+        """
         wizard = self.env['scop.bordereau.change.liasse.wizard']. \
             create({
                 'bordereau_id': self.id,
@@ -505,10 +523,13 @@ class Bordereau(models.Model):
         }
 
     def action_change_payment_mode(self):
+        """
+        :return: Ouvre le wizard pour changer le mode de paiement
+        """
         wizard = self.env['scop.bordereau.change.payment.mode.wizard']. \
             create({
-            'bordereau_id': self.id,
-        })
+                'bordereau_id': self.id,
+            })
         return {
             'type': 'ir.actions.act_window',
             'name': 'Changer le mode de paiement',
@@ -520,6 +541,11 @@ class Bordereau(models.Model):
         }
 
     def validate_ongoing_bordereau(self):
+        """
+        - Valide les invoices en brouillon
+        - Met à jour le numéro de version du bordereau
+        - Valide le versionnage en cours
+        """
         self.ensure_one()
         ongoing_version = self.check_ongoing_version()
         self.validate_bordereau()
@@ -532,6 +558,11 @@ class Bordereau(models.Model):
         })
 
     def cancel_ongoing_bordereau(self):
+        """
+        - Supprime les invoice en brouillon
+        - Réaffecte la dernière liasse fiscale (enregistrée dans la version)
+        - Supprime le versionnage en cours
+        """
         self.ensure_one()
         self.invoice_ids.filtered(
             lambda i: i.state == 'draft'
@@ -564,6 +595,9 @@ class Bordereau(models.Model):
     # Global Functions
     # ------------------------------------------------------
     def check_ongoing_version(self):
+        """
+        :return: le versionnage en cours
+        """
         ongoing_version = self.bordereau_version_ids.filtered(
             lambda v: v.version == self.version and v.state == 'new'
         )
@@ -672,20 +706,3 @@ class Bordereau(models.Model):
     def get_recipients(self):
         recipients = ','.join(map(lambda x: str(x), self.recipient_ids.ids))
         return recipients
-
-    # ------------------------------------------------------
-    # Threading task
-    # ------------------------------------------------------
-    def process_bordereau_validate(self):
-        with api.Environment.manage():
-            with registry(self.env.cr.dbname).cursor() as new_cr:
-                # Def new env
-                new_env = api.Environment(
-                    new_cr, self.env.uid, self.env.context
-                )
-                for bordereau in self.with_env(new_env):
-                    try:
-                        bordereau.validate_bordereau()
-                        bordereau.env.cr.commit()
-                    except Exception as e:
-                        _logger.exception(str(e))
diff --git a/models/scop_cotisation_cg.py b/models/scop_cotisation_cg.py
index 6f6960597cbda30b89f92aa85b5351489cf0183c..6ec2f6e2eb69ddb4f319b890de3687138e141682 100644
--- a/models/scop_cotisation_cg.py
+++ b/models/scop_cotisation_cg.py
@@ -4,12 +4,11 @@
 import base64
 import json
 import logging
-import threading
 import xlsxwriter
 from io import BytesIO
 from datetime import datetime
 
-from odoo import models, fields, api, exceptions, registry
+from odoo import models, fields, api, exceptions
 
 _logger = logging.getLogger(__name__)
 
@@ -242,19 +241,18 @@ class ScopCotisation(models.Model):
         """
         members_to_invoice = self.env['res.partner'].browse(*ids)
 
-        # Création de la task
-        cotiz_cg_task = self.env['scop.cotisation.task'].create({
-            'year': self.year,
-            'cotiz_to_create': len(members_to_invoice),
-            'message': "En cours de création",
-            'status': 'in_process'
-        })
-        cotiz_cg_task.env.cr.commit()
-        # Lancement du calcul en arrière plan
-        threaded_cotiz = threading.Thread(
-            target=self.process_cotiz_generate,
-            args=(members_to_invoice, cotiz_cg_task))
-        threaded_cotiz.start()
+        # Job queue
+        batch_name = (fields.Datetime.to_string(fields.Datetime.now()) +
+                      " Génération des bordereaux " + str(self.year))
+        batch = self.env['queue.job.batch'].get_new_batch(batch_name)
+        for member in members_to_invoice:
+            liasse_id = self.get_liasse(member)
+            self.with_context(
+                job_batch=batch
+            ).with_delay().create_bordereau(
+                member=member, liasse=liasse_id,
+                nb_quarter=4, date=False)
+        batch.enqueue()
 
     def cotiz_generate_wizard(self):
         if not self.trimester_1 or not self.trimester_2 or not self.trimester_3 or not self.trimester_4:
@@ -332,11 +330,11 @@ class ScopCotisation(models.Model):
         :param date:
         :return bordereau_id:
         """
-        existing_bordereau = self.env['scop.bordereau'].search([
+        bordereau = self.env['scop.bordereau'].search([
             ('partner_id', '=', member.id),
             ('year', '=', self.year),
         ])
-        if not existing_bordereau or is_regul:
+        if not bordereau or is_regul:
             # Variables to calculate cotiz
             staff_id = self.get_last_staff_id(member)
             if staff_id:
@@ -361,9 +359,8 @@ class ScopCotisation(models.Model):
                 'staff_shareholder_count': staff_shareholder_count,
                 'staff_average': staff_average,
             })
-            return bordereau
-        else:
-            return existing_bordereau
+        self.create_cotiz_and_lines(bordereau)
+        return bordereau.id
 
     def bordereau_validate(self):
         bordereau_to_validate = self.bordereau_ids.filtered(
@@ -873,62 +870,3 @@ class ScopCotisation(models.Model):
             else:
                 type_cotiz = 'ca'
         return type_cotiz
-
-    # ------------------------------------------------------
-    # Threading task
-    # ------------------------------------------------------
-    def process_cotiz_generate(self, partner_ids, cotiz_cg_task,
-                               nb_quarter=4, date=False):
-        """
-        Process de génération des cotiz CG en background
-        """
-        cotiz_created = 0
-        cotiz_to_create = len(partner_ids)
-
-        # Creation of cotiz invoice for each member
-        with api.Environment.manage():
-            with registry(self.env.cr.dbname).cursor() as new_cr:
-                # Def new env
-                new_env = api.Environment(
-                    new_cr, self.env.uid, self.env.context
-                )
-                # Def new var in new env
-                task = cotiz_cg_task.with_env(new_env)
-                new_self = self.with_env(new_env)
-
-                # Creation of cotiz invoice for each member
-                for member_id in partner_ids:
-                    member = member_id.with_env(new_env)
-                    liasse_id = new_self.get_liasse(member)
-                    try:
-                        # Bordereau
-                        bordereau = new_self.create_bordereau(
-                            member=member, liasse=liasse_id,
-                            nb_quarter=nb_quarter, date=date)
-                        bordereau.env.cr.commit()
-
-                        # Cotisations
-                        new_self.create_cotiz_and_lines(bordereau)
-
-                        cotiz_created += 1
-                        task.write({
-                            'cotiz_created': cotiz_created,
-                            'message': "%d / %d ont été créés" % (
-                                cotiz_created, cotiz_to_create),
-                        })
-                        if cotiz_created == cotiz_to_create:
-                            task.write({
-                                'message': "Tous les bordereaux ont été créés",
-                                'status': "done"
-                            })
-                        task.env.cr.commit()
-                    except Exception as e:
-                        _logger.exception(str(e))
-                        task.write({
-                            'cotiz_created': cotiz_created,
-                            'message': "%d / %d ont été créés" % (
-                                cotiz_created, cotiz_to_create),
-                            'is_error': True,
-                            'status': "done"
-                        })
-                        task.env.cr.commit()
diff --git a/wizard/scop_cotisation_cg_wizard.py b/wizard/scop_cotisation_cg_wizard.py
index a81e48473456e85387c2ce5c1f7a27ca4b6eba88..6d95f817006e42734621f7ecaea64a64b7538949 100644
--- a/wizard/scop_cotisation_cg_wizard.py
+++ b/wizard/scop_cotisation_cg_wizard.py
@@ -2,7 +2,6 @@
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
 import logging
-import threading
 
 from odoo import api, fields, models, exceptions
 
@@ -87,20 +86,20 @@ class ScopCotisationWizard(models.TransientModel):
             message_id = self.env['message.wizard'].create(
                 {'message': message})
 
-            # Création de la task
-            cotiz_cg_task = self.env['scop.cotisation.task'].create({
-                'year': self.year,
-                'cotiz_to_create': len(members_to_invoice),
-                'message': "En cours de création",
-                'status': 'in_process'
-            })
-            cotiz_cg_task.env.cr.commit()
-            # Lancement du calcul en arrière plan
-            threaded_cotiz = threading.Thread(
-                target=self.cotisation_cg_id.process_cotiz_generate,
-                args=(members_to_invoice, cotiz_cg_task,
-                      self.nb_quarter, self.date))
-            threaded_cotiz.start()
+            # Job queue
+            batch_name = (fields.Datetime.to_string(fields.Datetime.now()) +
+                          " Génération des bordereaux " +
+                          str(self.cotisation_cg_id.year))
+            batch = self.env['queue.job.batch'].get_new_batch(batch_name)
+            for member in members_to_invoice:
+                liasse_id = self.cotisation_cg_id.get_liasse(member)
+                self.cotisation_cg_id.with_context(
+                    job_batch=batch
+                ).with_delay().create_bordereau(
+                    member=member, liasse=liasse_id,
+                    nb_quarter=self.nb_quarter, date=self.date)
+            batch.enqueue()
+
         else:
             message = ("<p class='text-center'>Tous les bordereaux pour les "
                        "coops qui ont adhéré cette année avant le %s ont "