diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..75bb2042901930f807a588241612a29dd75e34d5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.*
+*.pyc
+!.gitignore
diff --git a/__init__.py b/__init__.py
index 8871070722787374e6f51f62f0f636847d986285..f88059b176b68c16a1a1024c635a43d555e9229c 100755
--- a/__init__.py
+++ b/__init__.py
@@ -1,6 +1,7 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
+# © 2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
 from . import controllers
 from . import models
+from . import report
 from . import wizard
diff --git a/__manifest__.py b/__manifest__.py
index 09e96df5398bb489d9cb21320540f9bbce31175a..54db846ab3ed89ec29ec6d4d43cd494a2f74f33f 100755
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -1,3 +1,5 @@
+# © 2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 {
     "name": "CG SCOP - Cotisations CG",
     "summary": "CG SCOP - Cotisations CG Scop",
@@ -11,25 +13,39 @@
         "l10n_fr",
         "lefilament_export_journal_tool",
         "cgscop_cotisation",
+        "queue_job_batch",
     ],
     "data": [
+        # Security
         "security/security_rules.xml",
         "security/ir.model.access.csv",
+        # Datas
+        "datas/bordereau_refund_wizard_quarter_data.xml",
         "datas/mail_data.xml",
+        "datas/queue_job_data.xml",
         "datas/ir_sequence_data.xml",
-        "wizard/scop_cotisation_cg_regul_wizard.xml",
-        "report/report_scop_bordereau.xml",
-        "report/report_scop_bordereau_payments.xml",
-        "report/report_scop_bordereau_refund.xml",
+        # Reports
+        "templates/report_scop_bordereau.xml",
+        "templates/report_scop_bordereau_payments.xml",
+        "templates/report_scop_bordereau_refund.xml",
+        # Views
         "views/account_invoice.xml",
         "views/res_config_settings.xml",
-        "views/scop_bordereau_cg.xml",
         "views/scop_cotisation_cg.xml",
         "views/scop_cotisation_simulation.xml",
         "views/scop_liasse_fiscale.xml",
+        # Wizards
         "wizard/export_journal_wizard_view.xml",
+        "wizard/scop_cotisation_cg_regul_wizard.xml",
+        "wizard/scop_bordereau_update_liasse_wizard.xml",
+        "wizard/scop_bordereau_payment_mode_wizard.xml",
+        "wizard/scop_bordereau_refund_wizard.xml",
         "wizard/scop_cotisation_cg_wizard.xml",
         "wizard/scop_bordereau_update_confirm_view.xml",
         "wizard/scop_bordereau_validate_confirm_view.xml",
+        # Wizard dependency view
+        "views/scop_bordereau_cg.xml",
+        # Menus
+        "views/menus.xml",
     ]
 }
diff --git a/datas/bordereau_refund_wizard_quarter_data.xml b/datas/bordereau_refund_wizard_quarter_data.xml
new file mode 100644
index 0000000000000000000000000000000000000000..213e9e1c3c7d87a3994aa33dae104d47dce78123
--- /dev/null
+++ b/datas/bordereau_refund_wizard_quarter_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="bordereau_wizard_quarter1" model="scop.bordereau.refund.wizard.quarter">
+            <field name="quarter">1</field>
+        </record>
+
+        <record id="bordereau_wizard_quarter2" model="scop.bordereau.refund.wizard.quarter">
+            <field name="quarter">2</field>
+        </record>
+        
+        <record id="bordereau_wizard_quarter3" model="scop.bordereau.refund.wizard.quarter">
+            <field name="quarter">3</field>
+        </record>
+        
+        <record id="bordereau_wizard_quarter4" model="scop.bordereau.refund.wizard.quarter">
+            <field name="quarter">4</field>
+        </record>
+        
+    </data>
+</odoo>
\ No newline at end of file
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/__init__.py b/models/__init__.py
index 14a36e45970b8b7d70501ae26d038f07fc6e1863..c34981509f9c6ecfd42f18c4df619cc48a4f5832 100755
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -5,6 +5,7 @@ from . import account_invoice
 from . import res_company
 from . import res_config_settings
 from . import scop_bordereau_cg
+from . import scop_bordereau_cg_version
 from . import scop_cotisation_simulation
-from . import scop_cotisation_cg
 from . import scop_liasse_fiscale
+from . import scop_cotisation_cg
diff --git a/models/account_invoice.py b/models/account_invoice.py
index ba7f3aebc1ec29a5b474512c1e11fb810bd10c48..b8c7e828bc0d64344d0483b78f2232874293c81d 100644
--- a/models/account_invoice.py
+++ b/models/account_invoice.py
@@ -7,104 +7,33 @@ from odoo import models, fields, api
 class ScopAccountInvoiceCG(models.Model):
     _inherit = "account.invoice"
 
-    cotisation_cg_id = fields.Many2one(
-        comodel_name='scop.cotisation.cg',
-        string='Base de cotisation CG Scop')
     bordereau_id = fields.Many2one(
         comodel_name='scop.bordereau',
         string='Bordereau de rattachement',
+        ondelete='cascade',
         required=False,)
+    cotisation_cg_id = fields.Many2one(
+        related='bordereau_id.base_cotisation_cg')
     amount_cg_calculated = fields.Monetary(
-        string="Montant calculé annuel", currency_field='company_currency_id',
-        readonly=True)
-    amount_cg_prorata = fields.Monetary(
-        string="Montant calculé proratisé",
-        currency_field='company_currency_id',
-        compute='_compute_amount_cg_prorata',
-        store=True, readonly=True)
+        string="Montant cotisation annuel",
+        currency_field='company_currency_id', readonly=True)
+    nb_quarter = fields.Selection(related='bordereau_id.nb_quarter')
+    cotiz_quarter = fields.Selection(
+        string='Trimestre',
+        selection=[(1, 1), (2, 2), (3, 3), (4, 4)],
+        required=False, )
 
     # ------------------------------------------------------
     # Compute fields
     # ------------------------------------------------------
-    @api.depends('amount_cg_calculated', 'nb_quarter')
-    @api.multi
-    def _compute_amount_cg_prorata(self):
-        for i in self:
-            prorata = i.nb_quarter / 4
-            i.amount_cg_prorata = i.cotisation_cg_id.\
-                round_to_closest_multiple(
-                    i.amount_cg_calculated * prorata, i.nb_quarter)
 
     # ------------------------------------------------------
     # Override parent
     # ------------------------------------------------------
-    @api.multi
-    def set_scop_contribution(self):
-        contrib_id = super(ScopAccountInvoiceCG, self).set_scop_contribution()
-        if self.cotisation_cg_id:
-            i = 4 - self.nb_quarter
-            schedule = {
-                'quarter_1': self.cotisation_cg_id.trimester_1,
-                'quarter_2': self.cotisation_cg_id.trimester_2,
-                'quarter_3': self.cotisation_cg_id.trimester_3,
-                'quarter_4': self.cotisation_cg_id.trimester_4,
-            }
-            while i != 0:
-                key = 'quarter_' + str(i)
-                schedule.pop(key, None)
-                i -= 1
-            contrib_id.update(schedule)
-        return contrib_id
-
-    def set_scop_contribution_hook(self, contrib_id):
-        """
-        Compute contribution line amount if bordereau regul
-        :param contrib_id:
-        :return:
-        """
-        super(ScopAccountInvoiceCG, self).set_scop_contribution_hook(contrib_id)
-        if self.bordereau_id:
-            invoice_ids = self.bordereau_id.invoice_ids.filtered(
-                lambda i: i.type_contribution_id == contrib_id.type_id
-            )
-            contrib_id.update({
-                'amount_calculated': sum(invoice_ids.mapped('amount_total_signed')),
-                'amount_called': sum(invoice_ids.mapped('amount_total_signed')),
-            })
-        return contrib_id
 
     # ------------------------------------------------------
     # Global functions
     # ------------------------------------------------------
-    def recalcul_cotiz_cg(self):
-        """
-        Affecte la valeur calculée à la première ligne cotisation
-        existante dans la facture
-        """
-        cotisation_cg = self.company_id.contribution_cg_id
-        cotisation_fede_com = self.company_id.contribution_fede_com_id
-        cotisation_fede_cae = self.company_id.contribution_fede_cae_id
-        cotisation_hdf = self.company_id.contribution_hdf_id
-        cotisation_med = self.company_id.contribution_med_id
-        invoice_line_cotisation_id = self.invoice_line_ids.filtered(
-            lambda r: r.product_id in (cotisation_cg,
-                                       cotisation_fede_com,
-                                       cotisation_fede_cae,
-                                       cotisation_hdf, cotisation_med))
-        if len(invoice_line_cotisation_id) == 0:
-            message_id = self.env['message.wizard'].create(
-                {'message': "Pas d'article cotisation sélectionné !"})
-            return {
-                'name': 'Action impossible',
-                'type': 'ir.actions.act_window',
-                'view_mode': 'form',
-                'res_model': 'message.wizard',
-                'res_id': message_id.id,
-                'target': 'new'
-            }
-        else:
-            invoice_line_cotisation_id[0].price_unit = self.amount_cg_prorata
-
     def view_cotiz(self):
         form_view = self.env.ref(
             'cgscop_cotisation_cg.invoice_form_scop_cg_inherited').id
diff --git a/models/scop_bordereau_cg.py b/models/scop_bordereau_cg.py
index f205842f627be8cbc0ea5e5bf4417d386b69a446..3328aceeaf8d5ff2434d1a4f7f72f9fabd06afb2 100644
--- a/models/scop_bordereau_cg.py
+++ b/models/scop_bordereau_cg.py
@@ -1,10 +1,9 @@
 # © 2021 Le Filament (<http://www.le-filament.com>)
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
-from odoo import fields, models, api, registry
+from odoo import fields, models, api
 from odoo.exceptions import UserError
 import logging
-import threading
 
 _logger = logging.getLogger(__name__)
 
@@ -48,6 +47,10 @@ class Bordereau(models.Model):
         string='Liasse fiscale de référence',
         readonly=True,
         track_visibility='onchange')
+    liasse_count = fields.Integer(
+        string='Nombre de liasses',
+        compute='_compute_liasse_count'
+    )
     type_liasse_fiscale = fields.Selection(
         string='Type de liasse',
         related='liasse_fiscale_id.type_id')
@@ -65,12 +68,6 @@ class Bordereau(models.Model):
         related='partner_id.ur_id',
         store=True
     )
-    payment_term_id = fields.Many2one(
-        comodel_name='account.payment.term',
-        string="Conditions de paiement",
-        required=True,
-        track_visibility = 'onchange'
-    )
     payment_mode_id = fields.Many2one(
         comodel_name='account.payment.mode', string="Mode de paiment",
         ondelete='restrict',
@@ -82,16 +79,21 @@ class Bordereau(models.Model):
         inverse_name='bordereau_id',
         string='Cotisations',
         required=False)
+    invoice_count = fields.Integer(
+        string='Nombre d\'appels',
+        compute='_compute_invoice_count'
+    )
 
     state = fields.Selection([
         ('new', 'Brouillon'),
+        ('ongoing', 'En cours de modification'),
         ('validated', 'Validé'),
         ('paid', 'Payé'),
         ('cancel', 'Annulé')],
         string="Statut",
         default='new',
         compute='_compute_state', store=True,
-        track_visibility='onchange',)
+        track_visibility='onchange', )
 
     company_id = fields.Many2one(
         comodel_name='res.company',
@@ -113,90 +115,53 @@ class Bordereau(models.Model):
         compute='_compute_amount_residual',
         store=True)
     nb_quarter = fields.Selection(
-        string='Nombre de trimestres de cotisation',
+        string='Nb de trimestres de cotisation',
         selection=[(1, '1'),
                    (2, '2'),
                    (3, '3'),
                    (4, '4')],
         default='4', required=True,
         track_visibility='onchange')
+    details = fields.Html('Détails', compute='_compute_details')
 
     # Assiettes for cotiz calcul
-    year_liasse_connu = fields.Integer(
-        string='Année de la liasse calculée',
+    year_liasse = fields.Integer(
+        string='Année de la liasse',
         related='liasse_fiscale_id.year',
-        track_visibility='onchange'
+        track_visibility='onchange',
+        oldname='year_liasse_retenue'
     )
-    year_liasse_retenue = fields.Integer(
-        string='Année de la liasse retenue',
-        track_visibility='onchange'
-    )
-    type_assiette_connu = fields.Selection(
-        string='Type d\'assiette de cotisation calculé',
-        selection=[('ca', 'CA'),
-                   ('va', 'VA'), ],
-        compute='_compute_type_assiette_connu',
-        readonly=True)
-    type_assiette_retenu = fields.Selection(
-        string='Type d\'assiette de cotisation retenu',
-        selection=[('ca', 'CA'),
-                   ('va', 'VA'), ],
-        compute='_compute_type_assiette_retenu',
-        store=True,
-        track_visibility='onchange')
-    montant_assiette = fields.Float(
-        string='Montant assiette de cotisation',
-        compute='_compute_montant_assiette')
-    ca_connu = fields.Float(
-        string='CA connu',
-        readonly=True,
-        track_visibility='onchange')
-    ca_retenu = fields.Float(
-        string='CA retenu',
-        track_visibility='onchange')
-    va_connu = fields.Float(
-        string='VA connu',
-        readonly=True,
-        track_visibility='onchange')
-    va_cg_retenu = fields.Float(
-        string='VA retenu pour cotisation CG',
-        track_visibility='onchange')
-    va_fede_com_retenu = fields.Float(
-        string='VA retenu pour cotisation Fede com',
-        track_visibility='onchange')
-    staff_count_connu = fields.Integer(
-        string='Effectif de la coop connu',
-        readonly=True)
-    staff_fede_com_count_retenu = fields.Integer(
-        string='Effectif de la coop retenu (Fédé Com)',
-        track_visibility='onchange')
-    staff_ur_med_count_retenu = fields.Integer(
-        string='Effectif de la coop retenu (UR)',
-        track_visibility='onchange')
-    staff_shareholder_count_connu = fields.Integer(
-        string='Effectif sociétaires de la coop connu',
-        readonly=True)
-    staff_shareholder_count_retenu = fields.Integer(
-        string='Effectif sociétaires de la coop retenu',
-        track_visibility='onchange')
-    staff_average_connu = fields.Float(
-        string='Effectif moyen de la coop connu',
-        readonly=True)
-    staff_average_retenu = fields.Float(
-        string='Effectif moyen de la coop retenu',
-        track_visibility='onchange')
-    net_results_connu = fields.Float(
-        string='Résultat net connu',
-        readonly=True)
-    net_results_retenu = fields.Float(
-        string='Résultat net retenu',
-        track_visibility='onchange')
-    wage_cg_connu = fields.Float(
-        string='Montant masse salariale connu',
-        readonly=True)
-    wage_cg_retenu = fields.Float(
-        string='Montant masse salariale retenu',
-        track_visibility='onchange')
+    type_assiette = fields.Selection(
+        related='liasse_fiscale_id.contribution_base_type', store=True)
+    montant_assiette = fields.Integer(
+        related='liasse_fiscale_id.contribution_base_amount', store=True)
+    ca = fields.Float(
+        string='CA',
+        compute='_compute_values_calculation', store=True,
+        track_visibility='onchange',
+        oldname='ca_retenu')
+    va = fields.Float(
+        string='VA',
+        compute='_compute_values_calculation', store=True,
+        track_visibility='onchange',
+        oldname='va_cg_retenu')
+    staff_count = fields.Integer(
+        string='Effectif de la coop',
+        readonly=True, oldname='staff_count_connu')
+    staff_shareholder_count = fields.Integer(
+        string='Effectif sociétaires de la coop',
+        readonly=True, oldname='staff_shareholder_count_retenu')
+    staff_average = fields.Float(
+        string='Effectif moyen de la coop',
+        readonly=True, oldname='staff_average_retenu')
+    net_results = fields.Float(
+        string='Résultat net',
+        compute='_compute_values_calculation', store=True,
+        oldname='net_results_retenu')
+    wage_cg = fields.Float(
+        string='Montant masse salariale',
+        compute='_compute_values_calculation', store=True,
+        oldname='wage_cg_retenu')
     is_sdd = fields.Boolean(
         'Au prélèvement',
         compute='compute_is_sdd',
@@ -211,10 +176,6 @@ class Bordereau(models.Model):
         comodel_name='scop.bordereau',
         string='Bordereau initial',
     )
-    move_reconciled = fields.Boolean(
-        'Paiements en cours',
-        compute='_compute_move_reconciled'
-    )
     # Emails management
     recipient_ids = fields.One2many(
         comodel_name='res.partner',
@@ -227,24 +188,48 @@ class Bordereau(models.Model):
     #     compute='_compute_emails'
     # )
 
+    # Historique des versions
+    bordereau_version_ids = fields.One2many(
+        comodel_name='scop.bordereau.version',
+        inverse_name='bordereau_id',
+        string='Historique'
+    )
+    has_outstanding = fields.Boolean(
+        string='Paiements en circulation',
+        compute='_compute_has_outstanding', store=True
+    )
+
     # ------------------------------------------------------
     # Compute
     # ------------------------------------------------------
+    @api.depends('liasse_fiscale_id')
     @api.multi
-    def _compute_name(self):
-        for bordereau in self:
-            bordereau.name = "Bordereau %s - %s" % (
-                bordereau.base_cotisation_cg.year,
-                bordereau.partner_id.name)
+    def _compute_values_calculation(self):
+        for r in self:
+            if r.liasse_fiscale_id:
+                liasse = r.liasse_fiscale_id
+                r.ca = liasse.revenue_cgsubv
+                r.va = r.base_cotisation_cg.get_va(liasse)
+                r.net_results = liasse.L2053_HN \
+                    if liasse.L2053_HN > 0 else liasse.L2051_DI
+                r.wage_cg = liasse.wage_cg
+            else:
+                r.ca = r.va = r.net_results = r.wage_cg = 0
 
-    @api.depends('invoice_ids.state')
+    @api.depends('invoice_ids.state',
+                 'bordereau_version_ids', 'bordereau_version_ids.state')
     @api.multi
     def _compute_state(self):
         for bordereau in self:
             draft_cotiz = bordereau.invoice_ids.filtered(
                 lambda cotiz: cotiz.state == 'draft'
             )
-            if draft_cotiz:
+            ongoing_version = bordereau.bordereau_version_ids.filtered(
+                lambda v: v.state == 'new'
+            )
+            if ongoing_version:
+                bordereau.state = 'ongoing'
+            elif draft_cotiz:
                 bordereau.state = 'new'
             else:
                 unpaid_cotiz = bordereau.invoice_ids.filtered(
@@ -261,7 +246,17 @@ class Bordereau(models.Model):
         for bordereau in self:
             bordereau.year = bordereau.base_cotisation_cg.year
 
-    @api.depends('invoice_ids', 'invoice_ids.amount_total_signed')
+    @api.multi
+    def _compute_invoice_count(self):
+        for r in self:
+            r.invoice_count = len(r.invoice_ids)
+
+    @api.multi
+    def _compute_liasse_count(self):
+        for r in self:
+            r.liasse_count = len(r.partner_id.liasse_fiscale_ids)
+
+    @api.depends('invoice_count', 'invoice_ids.amount_total_signed')
     @api.multi
     def _compute_amount_total_cotiz(self):
         for r in self:
@@ -288,35 +283,19 @@ class Bordereau(models.Model):
                 bordereau.recipient_ids = child_ids
 
     @api.multi
-    def _compute_type_assiette_connu(self):
-        for bordereau in self:
-            bordereau.type_assiette_connu = \
-                bordereau.base_cotisation_cg.get_type_assiette(
-                    bordereau.ca_connu, bordereau.va_connu)
-
-    @api.depends('ca_retenu', 'va_cg_retenu')
-    @api.multi
-    def _compute_type_assiette_retenu(self):
+    def _compute_type_assiette(self):
         for bordereau in self:
-            bordereau.type_assiette_retenu = \
+            bordereau.type_assiette = \
                 bordereau.base_cotisation_cg.get_type_assiette(
-                    bordereau.ca_retenu, bordereau.va_cg_retenu)
+                    bordereau.ca, bordereau.va)
 
     @api.multi
-    def _search_type_assiette_retenu(self, operator, value):
+    def _search_type_assiette(self, operator, value):
         recs = self.search([]).filtered(
-            lambda r: r.type_assiette_retenu == value)
+            lambda r: r.type_assiette == value)
         if recs:
             return [('id', 'in', [x.id for x in recs])]
 
-    @api.multi
-    def _compute_montant_assiette(self):
-        for bordereau in self:
-            if bordereau.type_assiette_retenu == 'ca':
-                bordereau.montant_assiette = bordereau.ca_retenu
-            else:
-                bordereau.montant_assiette = bordereau.va_cg_retenu
-
     @api.multi
     def compute_is_sdd(self):
         sdd_id = self.env.ref(
@@ -333,20 +312,6 @@ class Bordereau(models.Model):
         if recs:
             return [('id', 'in', [x.id for x in recs])]
 
-    @api.multi
-    def _compute_move_reconciled(self):
-        self.ensure_one()
-        payments_ids = self.env['account.payment'].search([
-            ('partner_id', '=', self.partner_id.id)])
-        payments = list(
-            map(lambda p: self.get_move_reconciled(p), payments_ids))
-        if True in payments:
-            payments.remove(True)
-        if payments:
-            self.move_reconciled = False
-        else:
-            self.move_reconciled = True
-
     @api.multi
     def _compute_is_liasse_previ(self):
         for bordereau in self:
@@ -355,18 +320,60 @@ class Bordereau(models.Model):
             else:
                 bordereau.is_liasse_previ = False
 
+    @api.depends('invoice_ids.residual')
+    @api.multi
+    def _compute_has_outstanding(self):
+        for r in self:
+            if r.invoice_ids:
+                if r.invoice_ids.filtered(lambda i: i.has_outstanding is True):
+                    r.has_outstanding = True
+                else:
+                    r.has_outstanding = False
+            else:
+                r.has_outstanding = False
+
+    @api.multi
+    def _compute_details(self):
+        for r in self:
+            contribs = r.invoice_ids.read_group(
+                [('id', 'in', r.invoice_ids.ids)],
+                ['type_contribution_id', 'amount_total_signed'],
+                ['type_contribution_id'])
+            detail = "<table class='o_group o_inner_group'>"
+            for contrib in contribs:
+                detail += ('<tr><td class="o_td_label font-weight-bold">'
+                           + str(contrib.get('type_contribution_id')[1])
+                           + '</td><td style="width: 100%;">'
+                           + str(
+                            contrib.get('amount_total_signed')) +
+                           ' €</td></tr>')
+            detail += "</table><table class='o_group o_inner_group'>"
+            for i in range(1, 5):
+                amount_echeance = round(sum(self.invoice_ids.filtered(
+                    lambda inv: inv.cotiz_quarter == i
+                ).mapped('amount_total_signed')), 2)
+                detail += '<tr><td class="o_td_label font-weight-bold">' \
+                          + 'Trimestre ' + str(i) \
+                          + '</td><td style="width: 100%;">' \
+                          + str(amount_echeance) + ' €</td></tr>'
+            detail += '</table>'
+            r.details = detail
+
     # ------------------------------------------------------
     # Button functions
     # ------------------------------------------------------
-    @api.multi
     def validate_cotiz_cg(self):
-        for bordereau in self:
-            for inv in bordereau.invoice_ids:
+        self.ensure_one()
+        for inv in self.invoice_ids:
+            if inv.state == 'draft':
+                if not inv.date_invoice:
+                    inv.update({
+                        'date_invoice': self.date_cotisation,
+                    })
                 inv.update({
-                    'date_invoice': bordereau.date_cotisation,
-                    'payment_mode_id': bordereau.payment_mode_id,
+                    'payment_mode_id': self.payment_mode_id,
                 })
-                if bordereau.is_sdd and not inv.mandate_id:
+                if self.is_sdd and not inv.mandate_id:
                     raise UserError(
                         "Vous ne pouvez pas valider une cotisation au "
                         "prélèvement sans mandat"
@@ -374,18 +381,29 @@ class Bordereau(models.Model):
                 else:
                     inv.action_invoice_open()
 
-    @api.multi
     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):
@@ -425,30 +443,139 @@ class Bordereau(models.Model):
                 'context': ctx,
             }
 
-    @api.multi
-    def update_cotiz_and_lines(self):
-        for bordereau in self:
-            if bordereau.state == 'new':
-                bordereau.base_cotisation_cg.create_cotiz_and_lines(bordereau)
+    def update_bordereau_with_liasse(self):
+        """
+        Supprime ou ajoute les appels de cotisations en fonction du
+        nombre de trimestres choisi et de la liasse
+        :return:
+        """
+        self.create_cotiz_and_lines()
 
     @api.multi
     def open_payment(self):
-        self.ensure_one()
-        payments_ids = self.env['account.payment'].search([
-            ('partner_id', '=', self.partner_id.id)])
-
-        payments = list(map(lambda p: self.get_move_reconciled(p) if self.get_move_reconciled(p) != True else None, payments_ids))
-        if True in payments:
-            payments.remove(True)
-        # Return Action
-        action = {
-            'name': 'Liste des paiements en cours - ' + self.partner_id.name,
+        action_context = {
+            'company_ids': [self.company_id.id],
+            'partner_ids': [
+                self.partner_id.commercial_partner_id.id],
+            'mode': 'customers'
+        }
+        return {
+            'type': 'ir.actions.client',
+            'tag': 'manual_reconciliation_view',
+            'context': action_context,
+        }
+
+    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(
+            'cgscop_cotisation_cg.invoice_form_scop_cg_inherited').id
+        return {
+            'type': 'ir.actions.act_window',
+            'name': 'Appels de cotisations',
+            'views': [
+                [tree_view_id, "tree"],
+                [form_view_id, "form"]
+            ],
+            'view_mode': 'form',
+            'res_model': 'account.invoice',
+            'target': 'current',
+            'domain': [('id', 'in', self.invoice_ids.ids)],
+        }
+
+    def action_show_liasse(self):
+        """
+        :return: Ouvre la vue des liasses liées au partenaire
+        """
+        return {
             'type': 'ir.actions.act_window',
-            'res_model': 'account.payment',
-            'view_mode': 'tree,form',
-            'domain': [('id', 'in', payments)]
+            'name': 'Liasses fiscales - ' + self.partner_id.name,
+            'views': [
+                [False, "tree"],
+                [False, "form"]
+            ],
+            'view_mode': 'form',
+            'res_model': 'scop.liasse.fiscale',
+            'target': 'current',
+            'domain': [('partner_id', '=', self.partner_id.id)],
         }
-        return action
+
+    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,
+            })
+        return {
+            'type': 'ir.actions.act_window',
+            'name': 'Changer la liasse',
+            'views': [[False, "form"]],
+            'view_mode': 'form',
+            'res_model': 'scop.bordereau.change.liasse.wizard',
+            'target': 'new',
+            'res_id': wizard.id
+        }
+
+    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,
+            })
+        return {
+            'type': 'ir.actions.act_window',
+            'name': 'Changer le mode de paiement',
+            'views': [[False, "form"]],
+            'view_mode': 'form',
+            'res_model': 'scop.bordereau.change.payment.mode.wizard',
+            'target': 'new',
+            'res_id': wizard.id
+        }
+
+    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()
+        self.write({
+            'name': self.name[0:10] + '-' + str(self.version + 1),
+            'version': self.version + 1,
+            'date_regul': ongoing_version.date,
+            'comment_regul': ongoing_version.comment,
+        })
+        ongoing_version.write({
+            'state': 'validated',
+        })
+
+    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'
+        ).unlink()
+        ongoing_version = self.check_ongoing_version()
+        self.write({
+            'liasse_fiscale_id': ongoing_version.liasse_fiscale_id_old.id
+        })
+        self.invoice_ids.update({
+            'liasse_fiscale_id': ongoing_version.liasse_fiscale_id_old.id
+        })
+        ongoing_version.unlink()
 
     # ------------------------------------------------------
     # Override ORM
@@ -463,19 +590,211 @@ class Bordereau(models.Model):
                 'avoirs sur les appels de cotisations.'
             )
         else:
-            for bordereau in self:
-                for cotiz in bordereau.invoice_ids:
-                    cotiz.unlink()
             return super(Bordereau, self).unlink()
 
     # ------------------------------------------------------
     # Global Functions
     # ------------------------------------------------------
+    def create_cotiz_and_lines(self):
+        """
+        - Supprime les factures existantes si besoin
+        - Crée les appels de cotisation par trimestre
+        """
+
+        if self.invoice_ids:
+            self.invoice_ids.unlink()
+
+        partner = self.partner_id
+        liasse = self.liasse_fiscale_id
+        base_cotiz = self.base_cotisation_cg
+
+        # Invoice cotiz CG
+        #
+        product_cg_id = self.company_id.contribution_cg_id
+        type_cotisation_cg = self.env.ref('cgscop_partner.riga_14397').id
+
+        if liasse:
+            amount_cg = base_cotiz.round_to_closest_multiple(
+                liasse.contribution_cg, 4)
+        else:
+            amount_cg = self.env['scop.liasse.fiscale']. \
+                get_values_for_cotiz_cg(partner)['plancher1']
+        self.create_contribution(
+            product_cg_id, type_cotisation_cg, amount_cg
+        )
+        self.env.cr.commit()
+
+        # Invoice UR et Fédé
+        type_cotisation_ur = self.env.ref('cgscop_partner.riga_14399').id
+        journal_ur_or_fede = self.company_id.contribution_ur_or_fede_journal_id
+
+        # Invoice cotiz Fede Com
+        #
+        if partner.is_federation_com:
+            product_fede_com_id = self.company_id.contribution_fede_com_id
+            account_id = self.company_id.receivable_account_fede_com_id
+            type_cotisation_fede_com = self.env.ref(
+                'cgscop_partner.riga_14398').id
+
+            if liasse:
+                amount_fede_com = base_cotiz.round_to_closest_multiple(
+                    liasse.contribution_com, 4)
+            else:
+                amount_fede_com = self.env['scop.liasse.fiscale']. \
+                    get_plancher_cotiz()['fede_com']
+            self.create_contribution(
+                product_fede_com_id, type_cotisation_fede_com, amount_fede_com,
+                journal_ur_or_fede, account_id
+            )
+            self.env.cr.commit()
+
+        # Invoice cotiz Fede CAE
+        #
+        if partner.cae:
+            product_fede_cae_id = self.company_id.contribution_fede_cae_id
+            account_id = self.company_id.receivable_account_fede_cae_id
+            type_cotisation_fede_cae = self.env.ref(
+                'cgscop_partner.cotiz_fede_cae').id
+
+            if liasse:
+                amount_fede_cae = base_cotiz.round_to_closest_multiple(
+                    liasse.contribution_cae, 4)
+            else:
+                amount_fede_cae = self.env['scop.liasse.fiscale']. \
+                    get_plancher_cotiz()['fede_cae']
+            self.create_contribution(
+                product_fede_cae_id, type_cotisation_fede_cae, amount_fede_cae,
+                journal_ur_or_fede, account_id
+            )
+            self.env.cr.commit()
+
+        # Invoice cotiz UR HDF
+        #
+        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
+        if partner.ur_id.id == ur_hdf:
+            product_hdf_id = self.company_id.contribution_hdf_id
+            account_id = self.company_id.receivable_account_ur_hdf_id
+
+            if liasse:
+                amount_hdf = base_cotiz.round_to_closest_multiple(
+                    liasse.contribution_hdf, 4)
+            else:
+                amount_hdf = self.env['scop.liasse.fiscale']. \
+                    get_plancher_cotiz()['ur_hdf']
+            self.create_contribution(
+                product_hdf_id, type_cotisation_ur, amount_hdf,
+                journal_ur_or_fede, account_id
+            )
+            self.env.cr.commit()
+
+        # Invoice cotiz UR Med
+        #
+        ur_med = self.env.ref('cgscop_partner.riga_14243').id
+        if partner.ur_id.id == ur_med:
+            product_med_id = self.company_id.contribution_med_id
+            account_id = self.company_id.receivable_account_ur_med_id
+
+            if liasse:
+                amount_med = base_cotiz.round_to_closest_multiple(
+                    liasse.contribution_med, 4)
+            else:
+                amount_med = self.env['scop.liasse.fiscale']. \
+                    get_plancher_cotiz()['ur_med']
+            self.create_contribution(
+                product_med_id, type_cotisation_ur, amount_med,
+                journal_ur_or_fede, account_id
+            )
+            self.env.cr.commit()
+
+    def create_contribution(
+            self, product, type_contribution, amount=0,
+            journal_id=False, account_id=False, type_invoice='out_invoice'):
+        """
+        Create invoice from Contribution Base
+        :param product: product_id
+        :param type_contribution: type_contribution (CG, UR, Fédé)
+        :param amount: contribution amount (float)
+        :param journal_id: journal
+        :param account_id: customer_account_id
+        :param type_invoice: invoice or refund
+        :return: invoice
+        """
+        Invoice = self.env['account.invoice']
+        InvoiceLine = self.env['account.invoice.line']
+        partner = self.partner_id
+        liasse = self.liasse_fiscale_id
+
+        base_cotiz = self.base_cotisation_cg
+        quarters = [base_cotiz.trimester_1, base_cotiz.trimester_2,
+                    base_cotiz.trimester_3, base_cotiz.trimester_4]
+
+        # TODO: Specific CAE calculation : to be deleted when 2022 is generated
+        type_contrib_cae = self.env.ref('cgscop_partner.cotiz_fede_cae').id
+        if type_contribution == type_contrib_cae and self.year == '2022':
+            amount = ((amount / 4) * 3) + 25
+        # ... End specific CAE 2022
+
+        for i in range(1, self.nb_quarter + 1):
+            cotiz_quarter = (4 - self.nb_quarter) + i
+
+            journal_id = self.company_id.contribution_journal_id \
+                if not journal_id else journal_id
+            account_id = partner.property_account_receivable_id \
+                if not account_id else account_id
+            member_invoice = Invoice.create({
+                'partner_id': partner.id,
+                'liasse_fiscale_id': liasse.id,
+                'type': type_invoice,
+                'year': self.year,
+                'is_contribution': True,
+                'type_contribution_id': type_contribution,
+                'journal_id': journal_id.id,
+                'state': 'draft',
+                'account_id': account_id.id,
+                'payment_mode_id': partner.customer_payment_mode_id.id,
+                'date_invoice': self.date_cotisation,
+                'date_due': quarters[cotiz_quarter - 1],
+                'bordereau_id': self.id,
+                'amount_cg_calculated': amount,
+                'cotiz_quarter': cotiz_quarter,
+            })
+
+            # Création de la ligne de cotisation
+            price_unit = amount / 4
+
+            # TODO: Specific CAE calculation : to be deleted when 2022 is generated
+            if type_contribution == type_contrib_cae and self.year == '2022':
+                if cotiz_quarter == 1:
+                    price_unit = 25
+                else:
+                    price_unit = (amount - 25) / 3
+            # ... End specific CAE 2022
+
+            InvoiceLine.create({
+                'invoice_id': member_invoice.id,
+                'product_id': product.id,
+                'account_id': product.property_account_income_id.id,
+                'invoice_line_tax_ids': [(6, 0, product.taxes_id.ids)],
+                'name': product.name + " T" + str(cotiz_quarter),
+                'price_unit': price_unit
+            })
+
+    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'
+        )
+        if len(ongoing_version) != 1:
+            raise ValueError('Erreur sur le versionnage de ce bordereau')
+        else:
+            return ongoing_version
+
     @api.multi
     def get_bordereau_move_line(self):
         """
-        Get payment dates for bordereau according to payment_term in bordereau
-        Use "compute" function from account.move
+        Get move line for invoices in bordereau
         :return: dict with date as key and amount (float) as value
         """
         MoveLine = self.env['account.move.line']
@@ -506,8 +825,7 @@ class Bordereau(models.Model):
     @api.multi
     def get_bordereau_move_line_with_payments(self):
         """
-        Get payment dates for bordereau according to payment_term in bordereau
-        Use "compute" function from account.move
+        Get payment dates for invoices in bordereau
         :return: dict with date as key and amount (float) as value
         """
         MoveLine = self.env['account.move.line']
@@ -515,7 +833,7 @@ class Bordereau(models.Model):
             inv_ids = bordereau.invoice_ids.ids
             schedule_plan = MoveLine.read_group(
                 [('invoice_id', 'in', inv_ids),
-                ('account_id.internal_type', '=', 'receivable')],
+                 ('account_id.internal_type', '=', 'receivable')],
                 fields=['date_maturity', 'credit', 'debit', 'amount_residual'],
                 groupby=['date_maturity:day'],
                 orderby='date_maturity',
@@ -556,39 +874,7 @@ class Bordereau(models.Model):
             ['type_contribution_id', 'amount_total_signed'],
             ['type_contribution_id'])
 
-    def get_move_reconciled(self, payment):
-        """
-        Check if payment is reconciled
-        :param payment: account.payment object
-        :return: True or payment_id
-        """
-        rec = True
-        for aml in payment.move_line_ids.filtered(lambda x: x.account_id.reconcile):
-            if not aml.reconciled:
-                rec = payment.id
-        return rec
-
     # Email
     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_cotiz_cg()
-                        if bordereau.name == 'Brouillon':
-                            bordereau.name = bordereau.env[
-                                'ir.sequence'].next_by_code('scop.bordereau')
-                        bordereau.env.cr.commit()
-                    except Exception as e:
-                        _logger.exception(str(e))
diff --git a/models/scop_bordereau_cg_version.py b/models/scop_bordereau_cg_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef5e3217445f0f93c3314280e4383a49a91914e5
--- /dev/null
+++ b/models/scop_bordereau_cg_version.py
@@ -0,0 +1,58 @@
+# © 2021 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from datetime import timedelta
+
+from odoo import fields, models, api
+from odoo.exceptions import ValidationError
+
+
+class BordereauVersion(models.Model):
+    _name = 'scop.bordereau.version'
+    _description = 'Historique des versions des bordereaux des cotisations CG'
+
+    bordereau_id = fields.Many2one(
+        comodel_name='scop.bordereau',
+        string='Bordereau de rattachement',
+        required=True,
+        readonly=True,
+        ondelete='cascade')
+    version = fields.Integer('Version du bordereau', readonly=True)
+    comment = fields.Char(string='Motif')
+    liasse_fiscale_id_old = fields.Many2one(
+        comodel_name='scop.liasse.fiscale',
+        string='Ancienne liasse fiscale',
+        ondelete='set null',
+        readonly=True
+    )
+    type_assiette = fields.Selection(
+        string='Ancien type d\'assiette',
+        selection=[('ca', 'CA'),
+                   ('va', 'VA'), ],
+        readonly=True)
+    date = fields.Date('Date', readonly=True)
+    montant_assiette = fields.Integer(
+        string='Ancien montant assiette', readonly=True)
+    company_currency_id = fields.Many2one(
+        related='bordereau_id.company_currency_id')
+    amount_total_cotiz = fields.Monetary(
+        string='Ancien montant cotisation',
+        currency_field='company_currency_id', readonly=True)
+    state = fields.Selection([
+        ('new', 'Brouillon'),
+        ('validated', 'Validée')],
+        string="Statut",
+        default='new', readonly=True)
+
+    # ------------------------------------------------------
+    # Constrain Functions
+    # ------------------------------------------------------
+    @api.constrains('state')
+    def check_unique_state_new(self):
+        """ Une seule version en brouillon par bordereau """
+        if len(self.bordereau_id.bordereau_version_ids.filtered(
+                lambda v: v.state == 'new'
+        )) > 1:
+            raise ValidationError(
+                'Vous devez valider ou annuler les versions de bordereaux en '
+                'cours de modification avant de créer une nouvelle version !')
diff --git a/models/scop_cotisation_cg.py b/models/scop_cotisation_cg.py
index a3a368253732728423113f0c527fb9ede80cce02..6ffd9f77cd37adc02e05eb5e119d76f238f39f76 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__)
 
@@ -41,7 +40,7 @@ class ScopCotisation(models.Model):
     bordereau_ids = fields.One2many(
         comodel_name='scop.bordereau',
         inverse_name='base_cotisation_cg',
-        string='Bordereau',)
+        string='Bordereau', )
 
     state = fields.Selection([
         ('new', 'Brouillon'),
@@ -49,7 +48,7 @@ class ScopCotisation(models.Model):
         ('end', 'Clôturé')],
         string="Statut", default='new',
         compute='_compute_state',
-        store=True, track_visibility='onchange',)
+        store=True, track_visibility='onchange', )
 
     invoice_count = fields.Integer(
         string='Appels de cotisations émis',
@@ -212,25 +211,14 @@ class ScopCotisation(models.Model):
                     str(self.invoiced_member_count) +
                     "<br/>Bordereaux à générer : " +
                     str(len(members_to_invoice)) +
-                    "<p>Les appels de cotisation sont en cours de "
-                    "création...</p> "
+                    "<p>Les appels de cotisation vont être générés.</p> "
             )
-            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.process_cotiz_generate,
-                args=(members_to_invoice, cotiz_cg_task))
-            threaded_cotiz.start()
+            message_id = self.env['message.wizard'].create({
+                    'message': message,
+                    'cancel_button': True,
+                    'action': 'action_cotiz_generate('
+                              + str(members_to_invoice.ids) + ')',
+                 })
         else:
             message = ("<p class='text-center'>Tous les appels de " +
                        "cotisations annuels ont déjà été créés !</p>")
@@ -246,6 +234,25 @@ class ScopCotisation(models.Model):
             'target': 'new'
         }
 
+    def action_cotiz_generate(self, *ids):
+        """
+        Function to be used by message.wizard in "ok" action
+        """
+        members_to_invoice = self.env['res.partner'].browse(*ids)
+
+        # 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:
             raise exceptions.UserError(
@@ -312,8 +319,7 @@ class ScopCotisation(models.Model):
             'target': 'current',
         }
 
-    def create_bordereau(
-            self, member, nb_quarter, liasse=None, date=False, is_regul=False):
+    def create_bordereau(self, member, nb_quarter, liasse=None, date=False):
         """
         Création du bordereau de cotisations
         :param member:
@@ -322,58 +328,32 @@ class ScopCotisation(models.Model):
         :param date:
         :return bordereau_id:
         """
-        existing_bordereau = self.env['scop.bordereau'].search([
-            ('partner_id', '=', member.id),
-            ('year', '=', self.year),
-        ])
-        if not existing_bordereau or is_regul:
-            # Variables to calculate cotiz
-            ca = liasse.revenue_cgsubv
-            va = self.get_va(liasse)
-            staff_id = self.get_last_staff_id(member)
-            if staff_id:
-                staff_shareholder_count = \
-                    staff_id.staff_shareholder_count
-                staff_count = \
-                    staff_id.staff_count
-            else:
-                staff_shareholder_count = 0
-                staff_count = 0
+        # Variables to calculate cotiz
+        staff_id = self.get_last_staff_id(member)
+        if staff_id:
+            staff_shareholder_count = staff_id.staff_shareholder_count
+            staff_count = staff_id.staff_count
             staff_average = staff_id.staff_average
-            net_results = liasse.L2053_HN \
-                if liasse.L2053_HN > 0 else liasse.L2051_DI
-            wage_cg = liasse.wage_cg
-            date_invoice = date if date else self.date_cotisation
-
-            bordereau = self.env['scop.bordereau'].create({
-                'partner_id': member.id,
-                'payment_mode_id': member.customer_payment_mode_id.id,
-                'base_cotisation_cg': self.id,
-                'payment_term_id': self.payment_term_id.id,
-                'liasse_fiscale_id': liasse.id if liasse else None,
-                'year_liasse_retenue': liasse.year if liasse else 0,
-                'date_cotisation': date_invoice,
-                'nb_quarter': nb_quarter,
-                'ca_connu': ca,
-                'ca_retenu': ca,
-                'va_connu': va,
-                'va_cg_retenu': va,
-                'va_fede_com_retenu': va,
-                'staff_count_connu': staff_count,
-                'staff_fede_com_count_retenu': staff_count,
-                'staff_ur_med_count_retenu': staff_count,
-                'staff_shareholder_count_connu': staff_shareholder_count,
-                'staff_shareholder_count_retenu': staff_shareholder_count,
-                'staff_average_connu': staff_average,
-                'staff_average_retenu': staff_average,
-                'net_results_connu': net_results,
-                'net_results_retenu': net_results,
-                'wage_cg_connu': wage_cg,
-                'wage_cg_retenu': wage_cg,
-            })
-            return bordereau
         else:
-            return existing_bordereau
+            staff_shareholder_count = 0
+            staff_count = 0
+            staff_average = 0
+        date_invoice = date if date else self.date_cotisation
+
+        bordereau = self.env['scop.bordereau'].create({
+            'partner_id': member.id,
+            'payment_mode_id': member.customer_payment_mode_id.id,
+            'base_cotisation_cg': self.id,
+            'liasse_fiscale_id': liasse.id if liasse else None,
+            'year_liasse': liasse.year if liasse else 0,
+            'date_cotisation': date_invoice,
+            'nb_quarter': nb_quarter,
+            'staff_count': staff_count,
+            'staff_shareholder_count': staff_shareholder_count,
+            'staff_average': staff_average,
+        })
+        bordereau.create_cotiz_and_lines()
+        return bordereau.id
 
     def bordereau_validate(self):
         bordereau_to_validate = self.bordereau_ids.filtered(
@@ -387,7 +367,7 @@ class ScopCotisation(models.Model):
             )
         else:
             message = (
-                    "Tous les bordereaux ont déjà été validés"
+                "Tous les bordereaux ont déjà été validés"
             )
         message_id = self.env['message.wizard'].create(
             {'message': message})
@@ -468,9 +448,11 @@ class ScopCotisation(models.Model):
 
             # Calcul cotisation N-1
             contribution_last_year = sum(line_ids.filtered(
-                lambda l: l.product_id == product_cg_id).mapped('price_subtotal_signed'))
+                lambda l: l.product_id == product_cg_id).mapped(
+                'price_subtotal_signed'))
 
             # Construction Tableau
+            liasse.read(['revenue_cg', 'av_cg', 'wage_cg'])
             datas_contrib = [
                 m.member_number,
                 m.ur_id.name,
@@ -502,7 +484,8 @@ class ScopCotisation(models.Model):
                         liasse.contribution_hdf, 4) if liasse else 40
                     # Calcul cotisation N-1
                     contribution_last_year = sum(line_ids.filtered(
-                        lambda l: l.product_id == product_hdf_id).mapped('price_subtotal_signed'))
+                        lambda l: l.product_id == product_hdf_id).mapped(
+                        'price_subtotal_signed'))
                     datas_contrib[4] = 'Cotisation UR HDF'
                     datas_contrib[5] = contrib_hdf
                     datas_contrib[6] = contribution_last_year
@@ -517,7 +500,8 @@ class ScopCotisation(models.Model):
                         liasse.contribution_med, 4) if liasse else 0
                     # Calcul cotisation N-1
                     contribution_last_year = sum(line_ids.filtered(
-                        lambda l: l.product_id == product_med_id).mapped('price_subtotal_signed'))
+                        lambda l: l.product_id == product_med_id).mapped(
+                        'price_subtotal_signed'))
                     datas_contrib[4] = 'Cotisation UR Méditerranée'
                     datas_contrib[5] = contrib_med
                     datas_contrib[6] = contribution_last_year
@@ -540,7 +524,8 @@ class ScopCotisation(models.Model):
                             contrib_fede_com = 108
                     # Calcul cotisation N-1
                     contribution_last_year = sum(line_ids.filtered(
-                        lambda l: l.product_id == product_com_id).mapped('price_subtotal_signed'))
+                        lambda l: l.product_id == product_com_id).mapped(
+                        'price_subtotal_signed'))
                     datas_contrib[4] = 'Cotisation Fédération de la Com'
                     datas_contrib[5] = contrib_fede_com
                     datas_contrib[6] = contribution_last_year
@@ -552,7 +537,8 @@ class ScopCotisation(models.Model):
                     contrib_fede_cae = 100
                     # Calcul cotisation N-1
                     contribution_last_year = sum(line_ids.filtered(
-                        lambda l: l.product_id == product_cae_id).mapped('price_subtotal_signed'))
+                        lambda l: l.product_id == product_cae_id).mapped(
+                        'price_subtotal_signed'))
                     datas_contrib[4] = 'Cotisation Fédération des CAE'
                     datas_contrib[5] = contrib_fede_cae
                     datas_contrib[6] = contribution_last_year
@@ -563,7 +549,9 @@ class ScopCotisation(models.Model):
             total_cg += contrib_cg
 
         # Génération du ficher Excel
-        file_name = datetime.strftime(datetime.now(), '%Y-%m-%d_%Hh%M') + ' Simulation cotisations ' + str(self.year) + '.xlsx'
+        file_name = datetime.strftime(datetime.now(),
+                                      '%Y-%m-%d_%Hh%M') + ' Simulation cotisations ' + str(
+            self.year) + '.xlsx'
         output = BytesIO()
         workbook = xlsxwriter.Workbook(output, {'in_memory': True})
         worksheet1 = workbook.add_worksheet('Données brutes')
@@ -644,314 +632,9 @@ class ScopCotisation(models.Model):
         else:
             return Liasse
 
-    def create_cotiz_and_lines(self, bordereau, date=False, is_regul=False):
-
-        partner = bordereau.partner_id
-        liasse = bordereau.liasse_fiscale_id
-
-        # Invoice cotiz CG
-        #
-        product_cg_id = self.company_id.contribution_cg_id
-        type_cotisation_cg = self.env.ref('cgscop_partner.riga_14397').id
-
-        amount_cg = self.round_to_closest_multiple(
-            self.get_cotiz_cg(partner, bordereau)
-            , 4)
-        invoice_cotiz_cg = self.create_contribution(
-            product_cg_id, partner, type_cotisation_cg,
-            liasse, amount_cg, date, is_regul=is_regul, bordereau=bordereau)
-        invoice_cotiz_cg.write({
-            'cotisation_cg_id': self.id,
-            'bordereau_id': bordereau.id,
-            'amount_cg_calculated': amount_cg,
-            'nb_quarter': bordereau.nb_quarter
-        })
-        if bordereau.nb_quarter != 4:
-            invoice_cotiz_cg.recalcul_cotiz_cg()
-        invoice_cotiz_cg.env.cr.commit()
-
-        # Invoice UR et Fédé
-        type_cotisation_ur = self.env.ref('cgscop_partner.riga_14399').id
-        journal_ur_or_fede = self.company_id.contribution_ur_or_fede_journal_id
-
-        # Invoice cotiz Fede Com
-        #
-        if partner.is_federation_com:
-            product_fede_com_id = self.company_id.contribution_fede_com_id
-            account_id = self.company_id.receivable_account_fede_com_id
-            type_cotisation_fede_com = self.env.ref(
-                'cgscop_partner.riga_14398').id
-
-            amount_fede_com = self.round_to_closest_multiple(
-                self.get_cotiz_fede_com(bordereau)
-                , 4)
-            invoice_cotiz_fede_com = self.create_contribution(
-                product_fede_com_id, partner, type_cotisation_fede_com,
-                liasse, amount_fede_com, date, journal_ur_or_fede, account_id,
-                is_regul=is_regul, bordereau=bordereau)
-            invoice_cotiz_fede_com.write({
-                'cotisation_cg_id': self.id,
-                'bordereau_id': bordereau.id,
-                'amount_cg_calculated': amount_fede_com,
-                'nb_quarter': bordereau.nb_quarter
-            })
-            if bordereau.nb_quarter != 4:
-                invoice_cotiz_fede_com.recalcul_cotiz_cg()
-            invoice_cotiz_fede_com.env.cr.commit()
-
-        # Invoice cotiz Fede CAE
-        #
-        if partner.cae:
-            product_fede_cae_id = self.company_id.contribution_fede_cae_id
-            account_id = self.company_id.receivable_account_fede_cae_id
-            type_cotisation_fede_cae = self.env.ref(
-                'cgscop_partner.cotiz_fede_cae').id
-
-            amount_fede_cae = self.round_to_closest_multiple(
-                self.get_cotiz_fede_cae(), 4)
-            invoice_cotiz_fede_cae = self.create_contribution(
-                product_fede_cae_id, partner, type_cotisation_fede_cae,
-                liasse, amount_fede_cae, date, journal_ur_or_fede, account_id,
-                is_regul=is_regul, bordereau=bordereau
-            )
-            invoice_cotiz_fede_cae.write({
-                'cotisation_cg_id': self.id,
-                'bordereau_id': bordereau.id,
-                'amount_cg_calculated': amount_fede_cae,
-                'nb_quarter': bordereau.nb_quarter
-            })
-            if bordereau.nb_quarter != 4:
-                invoice_cotiz_fede_cae.recalcul_cotiz_cg()
-            invoice_cotiz_fede_cae.env.cr.commit()
-
-        # Invoice cotiz UR HDF
-        #
-        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
-        if partner.ur_id.id == ur_hdf:
-            product_hdf_id = self.company_id.contribution_hdf_id
-            account_id = self.company_id.receivable_account_ur_hdf_id
-
-            amount_hdf = self.round_to_closest_multiple(
-                self.get_cotiz_hdf(bordereau), 4)
-            invoice_cotiz_hdf = self.create_contribution(
-                product_hdf_id, partner, type_cotisation_ur,
-                liasse, amount_hdf, date, journal_ur_or_fede, account_id,
-                is_regul=is_regul, bordereau=bordereau
-            )
-            invoice_cotiz_hdf.write({
-                'cotisation_cg_id': self.id,
-                'bordereau_id': bordereau.id,
-                'amount_cg_calculated': amount_hdf,
-                'nb_quarter': bordereau.nb_quarter
-            })
-            if bordereau.nb_quarter != 4:
-                invoice_cotiz_hdf.recalcul_cotiz_cg()
-            invoice_cotiz_hdf.env.cr.commit()
-
-        # Invoice cotiz UR Med
-        #
-        ur_med = self.env.ref('cgscop_partner.riga_14243').id
-        if partner.ur_id.id == ur_med:
-            product_med_id = self.company_id.contribution_med_id
-            account_id = self.company_id.receivable_account_ur_med_id
-
-            amount_med = self.round_to_closest_multiple(
-                self.get_cotiz_med(amount_cg, bordereau), 4)
-            invoice_cotiz_med = self.create_contribution(
-                product_med_id, partner, type_cotisation_ur,
-                liasse, amount_med, date, journal_ur_or_fede, account_id,
-                is_regul=is_regul, bordereau=bordereau)
-            invoice_cotiz_med.write({
-                'cotisation_cg_id': self.id,
-                'bordereau_id': bordereau.id,
-                'amount_cg_calculated': amount_med,
-                'nb_quarter': bordereau.nb_quarter
-            })
-            if bordereau.nb_quarter != 4:
-                invoice_cotiz_med.recalcul_cotiz_cg()
-            invoice_cotiz_med.env.cr.commit()
-
     # ------------------------------------------------------
     # Calcul des cotisations
     # ------------------------------------------------------
-
-    # TODO: A voir si on conserve ces fonctions.
-    #       --
-    #       Le montant des cotisations est calculé depuis la liasse, à vois si il est nécessaire
-    #       de conserver ces fonctions :
-    #        - si il y a une liasse, on applique les montants de la liasse
-    #        - si il n'y en a pas, on applique la valeur plancher (auquel cas, on supprime ces fonctions)
-    #       A checker également pour les ajustements, les modifications et les exonérations
-    #       --
-    #       Hypothèse :
-    #        - soit on a la liasse fiscale et on ajuste via les données de la liasse
-    #        - soit on ajuste manuelement le calcul
-    #       => A valider par Hervé + Christophe (et faire une revue du code de recalcul des cotisations)
-
-    def get_cotiz_cg(self, partner, bordereau):
-        """
-            Appelle la fonction de calcul de la cotisation CG Scop
-            à partir des variables du bordereau
-        """
-
-        type_assiette = bordereau.type_assiette_retenu
-        ca = self.check_dureeExercice(
-            bordereau.ca_retenu, bordereau.dureeExercice)
-        va = self.check_dureeExercice(
-            bordereau.va_cg_retenu, bordereau.dureeExercice)
-        return self.calc_cotiz_cg(partner, ca, va, type_assiette)
-
-    def calc_cotiz_cg(self, partner, ca, va, type_assiette):
-        """
-            Calcule la cotisation de la CG Scop :
-            - VA = VA saisie ou VA au sens CGSCOP si pas de VA renseignée
-            - 0,3% du CA ou 0,7% de la VA
-            - 300 € pour CA compris entre 0 et 100 K€
-            - 600 € pour CA compris entre 100 et 200 K€
-            - Max = 375 K€
-
-            Utilisation de hack_check_exercice pour avoir la valeur non
-            proratisée de la cotisation pour le calcul de la cotisation UR med
-
-            @return float : cotisation
-        """
-        values = self.get_values_for_cotiz_cg(partner)
-        if type_assiette == 'ca':
-            rate = self.get_rate_ca(partner)
-            cotiz = ca * rate
-        else:
-            rate = self.get_rate_va(partner)
-            cotiz = va * rate
-
-        if cotiz < values['plancher1']:
-            return values['plancher1']
-        elif cotiz < values['plancher2']:
-            return values['plancher2']
-        elif cotiz >= values['plancher3']:
-            if type_assiette == 'ca':
-                cotiz = (25000000 * rate) + (ca - 25000000) * (rate / 2)
-            else:
-                cotiz = (10714286 * rate) + (va - 10714286) * (rate / 2)
-            if cotiz <= values['plafond']:
-                return cotiz
-            else:
-                return values['plafond']
-        else:
-            return cotiz
-
-    def get_cotiz_fede_com(self, bordereau):
-        """
-            Calcule la cotisation de la fédération de la com pour 1 partenaire
-            - Assiette annuelle : VA saisie ou VA au sens CGSCOP
-            - Taux : 0.0032
-            - Calcul : Valeur Ajoutée * 0.0032
-            - Pour les nouvelles coopératives (pas de comptes annuels) :
-                108 € par salarié (effectif moyen s’il est saisi, à défaut
-                effectif), soit 27 € par salarié et par trimestre.
-            - Plancher annuel : 108 €
-            - Plafond annuel : 18 428 €
-
-            @return float : cotisation
-        """
-        plancher = 108
-        plafond = 18428
-        rate = 0.0032
-        va = self.check_dureeExercice(
-            bordereau.va_fede_com_retenu, bordereau.dureeExercice)
-        staff_average = bordereau.staff_average_retenu
-        staff_count = bordereau.staff_fede_com_count_retenu
-        if va != 0:
-            cotiz = va * rate
-        else:
-            if staff_average > 0:
-                cotiz = staff_average * plancher
-            else:
-                cotiz = staff_count * plancher
-        if plancher <= cotiz <= plafond:
-            return cotiz
-        elif cotiz < plancher:
-            return plancher
-        else:
-            return plafond
-
-    def get_cotiz_hdf(self, bordereau):
-        """
-            Calcule la cotisation de l'UR HDF pour 1 partenaire :
-            - 0,1 % de la masse salariale annuelle brute prévisionnelle
-            ou figurant sur la liasse fiscale.
-
-            @return float : cotisation
-        """
-        rate = 0.001
-        plancher = 40
-        wage_cg = self.check_dureeExercice(
-            bordereau.wage_cg_retenu, bordereau.dureeExercice)
-        if wage_cg > 0:
-            cotiz = wage_cg * rate
-        else:
-            cotiz = 0
-
-        if cotiz > plancher:
-            return cotiz
-        else:
-            return plancher
-
-    def get_cotiz_med(self, cotiz_cg, bordereau):
-        """
-            Calcule la cotisation de l'UR Med pour 1 partenaire :
-            - Assiette : Assiette de la cotisation CGSCOP
-            - Taux d’appel : 1/3 du taux
-            - Calcul intermédiaire : Assiette * taux
-                (soit 1/3 de la cotisation CGSCOP sans plancher)
-            - Complément de cotisation : 1% du résultat net si positif
-            - Abattement pour sociétariat :
-                Taux de sociétariat =   nombre de salariés sociétaires /
-                                        nombre de salariés
-                Abattement 20 % si >= 50 %
-                Abattement 30 % si >= 80 %
-            - Calcul cotisations :
-                [(Assiette*taux) + (résultat net *0.01)]* (1 ou 0.8 ou 0.7)
-
-            @return float : cotisation
-        """
-        # Assiette CG
-        assiette_rate = 1/3
-        assiette = cotiz_cg
-
-        # Résultat net
-        net_results_rate = 0.01
-
-        net_results = self.check_dureeExercice(
-            bordereau.net_results_retenu, bordereau.dureeExercice)
-        staff_count = bordereau.staff_shareholder_count_retenu
-        staff_shareholder_count = bordereau.staff_ur_med_count_retenu
-
-        # Taux d'abattement pour sociétariat
-        if staff_count > 0:
-            societariat_rate = staff_shareholder_count / staff_count
-        else:
-            societariat_rate = 0
-
-        if 0.5 <= societariat_rate < 0.8:
-            abatt_rate = 1 - 0.2
-        elif societariat_rate >= 0.8:
-            abatt_rate = 1 - 0.3
-        else:
-            abatt_rate = 1 - 0
-
-        # Cotiz
-        cotiz = ((assiette * assiette_rate) +
-                 (net_results * net_results_rate)) * abatt_rate
-        final_cotiz = cotiz if cotiz >= 0 else 0
-        return final_cotiz
-
-    def get_cotiz_fede_cae(self):
-        """
-            100€ if partner is CAE
-        """
-        cotiz = 100
-        return cotiz
-
     def get_va(self, liasse):
         """
         VA saisie ou VA au sens CGSCOP
@@ -959,6 +642,7 @@ class ScopCotisation(models.Model):
         :param liasse:
         :return:
         """
+        liasse.read(['av_lf', 'av_cg'])
         va = liasse.av_lf if liasse.av_lf > 0 else liasse.av_cg
         return va
 
@@ -989,112 +673,3 @@ class ScopCotisation(models.Model):
             else:
                 type_cotiz = 'ca'
         return type_cotiz
-
-    def get_rate_ca(self, partner):
-        # Calcul des Taux SCOP en fonction du type
-        if partner.cooperative_form_id in (
-                self.env.ref('cgscop_partner.form_coop47'),
-                self.env.ref('cgscop_partner.form_lamaneur')):
-            rate_ca = 0.002
-        else:
-            rate_ca = 0.003
-        return rate_ca
-
-    def get_rate_va(self, partner):
-        # Calcul des Taux SCOP en fonction du type
-        if partner.cooperative_form_id in (
-                self.env.ref('cgscop_partner.form_coop47'),
-                self.env.ref('cgscop_partner.form_lamaneur')):
-            rate_va = 0.0047
-        else:
-            rate_va = 0.007
-        return rate_va
-
-    def get_values_for_cotiz_cg(self, partner):
-        # Calcul des Taux SCOP en fonction du type
-        plancher1 = 300
-        plancher2 = 600
-        plancher3 = 75000
-        plafond = 375000
-        if partner.cooperative_form_id in (
-                self.env.ref('cgscop_partner.form_coop47'),
-                self.env.ref('cgscop_partner.form_lamaneur')):
-            plancher1 = 1/3 * plancher1
-            plancher2 = 1/3 * plancher2
-            plancher3 = 1/3 * plancher3
-            plafond = 1/3 * plafond
-
-        return {
-            'plancher1': plancher1,
-            'plancher2': plancher2,
-            'plancher3': plancher3,
-            'plafond': plafond,
-                }
-
-    def check_dureeExercice(self, amount, duree_exercice):
-        if duree_exercice and duree_exercice not in (0, 12):
-            return amount * (12/duree_exercice)
-        else:
-            return amount
-
-    # ------------------------------------------------------
-    # 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=bordereau, date=date
-                        )
-
-                        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/models/scop_liasse_fiscale.py b/models/scop_liasse_fiscale.py
index 98f01816e63848163dd15efde5551391c33b76cb..a736ec9313ce5bf7c1f9877779810d14e39b34cf 100644
--- a/models/scop_liasse_fiscale.py
+++ b/models/scop_liasse_fiscale.py
@@ -33,6 +33,10 @@ class ScopLiasseFiscale(models.Model):
         string='Cotisation Fédération Com',
         compute='_compute_contribution_com',
         store=True)
+    contribution_cae = fields.Float(
+        string='Cotisation Fédération CAE',
+        compute='_compute_contribution_cae',
+        store=True)
 
     # ------------------------------------------------------
     # Compute fields
@@ -52,6 +56,7 @@ class ScopLiasseFiscale(models.Model):
         """
         for liasse in self:
             # Calcul VA
+            liasse.read(['av_lf', 'av_cg', 'revenue_cg'])
             va = liasse.av_lf if liasse.av_lf > 0 else liasse.av_cg
             ca = liasse.revenue_cg
             if liasse.dureeExercice and liasse.dureeExercice not in (0, 12):
@@ -116,9 +121,10 @@ class ScopLiasseFiscale(models.Model):
         """
         ur_hdf = self.env.ref('cgscop_partner.riga_14232')
         for liasse in self:
+            plancher = liasse.get_plancher_cotiz()['ur_hdf']
+            liasse.read(['wage_cg'])
             if liasse.partner_id.ur_id == ur_hdf:
                 rate = 0.001
-                plancher = 40
                 if liasse.dureeExercice and liasse.dureeExercice not in (0, 12):
                     wage_cg = liasse.wage_cg * (12/liasse.dureeExercice)
                 else:
@@ -133,6 +139,67 @@ class ScopLiasseFiscale(models.Model):
                 else:
                     liasse.contribution_hdf = plancher
 
+    @api.depends('contribution_cg', 'L2053_HN')
+    @api.multi
+    def _compute_contribution_med(self):
+        """
+            Calcule la cotisation de l'UR Med pour 1 liasse :
+            - Assiette : Assiette de la cotisation CGSCOP
+            - Taux d’appel : 1/3 du taux
+            - Calcul intermédiaire : Assiette * taux
+                (soit 1/3 de la cotisation CGSCOP sans plancher)
+            - Complément de cotisation : 1% du résultat net si positif
+            - Abattement pour sociétariat :
+                Taux de sociétariat =   nombre de salariés sociétaires /
+                                        nombre de salariés
+                Abattement 20 % si >= 50 %
+                Abattement 30 % si >= 80 %
+            - Calcul cotisations :
+                [(Assiette*taux) + (résultat net *0.01)]* (1 ou 0.8 ou 0.7)
+
+            @return float : cotisation
+        """
+        ur_med = self.env.ref('cgscop_partner.riga_14243')
+        for liasse in self:
+            plancher = liasse.get_plancher_cotiz()['ur_med']
+            if liasse.partner_id.ur_id == ur_med:
+                # Assiette CG
+                assiette_rate = 1/3
+                assiette = liasse.contribution_cg
+
+                # Résultat net
+                net_results_rate = 0.01
+                net_results = liasse.L2053_HN if liasse.L2053_HN > 0 else liasse.L2051_DI
+                if liasse.dureeExercice and liasse.dureeExercice not in (0, 12):
+                    net_results = net_results * (12/liasse.dureeExercice)
+
+                # Effectifs
+                staff_id = self.get_last_staff_id(liasse.partner_id)
+                if staff_id:
+                    staff_shareholder_count = staff_id.staff_shareholder_count
+                    staff_count = staff_id.staff_count
+                else:
+                    staff_shareholder_count = staff_count = 0
+
+                # Taux d'abattement pour sociétariat
+                if staff_count > 0:
+                    societariat_rate = staff_shareholder_count / staff_count
+                else:
+                    societariat_rate = 0
+
+                if 0.5 <= societariat_rate < 0.8:
+                    abatt_rate = 1 - 0.2
+                elif societariat_rate >= 0.8:
+                    abatt_rate = 1 - 0.3
+                else:
+                    abatt_rate = 1 - 0
+
+                # Calcul Cotisation
+                contribution_med = ((assiette * assiette_rate) +
+                         (net_results * net_results_rate)) * abatt_rate
+                final_contribution_med = contribution_med if contribution_med >= 0 else plancher
+                liasse.contribution_med = final_contribution_med
+
     @api.depends('av_lf', 'av_cg')
     @api.multi
     def _compute_contribution_com(self):
@@ -149,10 +216,11 @@ class ScopLiasseFiscale(models.Model):
 
             @return float : cotisation
         """
-        plancher = 108
         plafond = 18428
         rate = 0.0032
         for liasse in self:
+            plancher = liasse.get_plancher_cotiz()['fede_com']
+            liasse.read(['av_lf', 'av_cg'])
             if liasse.partner_id.is_federation_com:
                 # Calcul VA
                 va = liasse.av_lf if liasse.av_lf > 0 else liasse.av_cg
@@ -187,69 +255,64 @@ class ScopLiasseFiscale(models.Model):
                 else:
                     liasse.contribution_com = plafond
 
-    @api.depends('contribution_cg', 'L2053_HN')
+    @api.depends('L2052_FY', 'partner_id.cae')
     @api.multi
-    def _compute_contribution_med(self):
+    def _compute_contribution_cae(self):
         """
-            Calcule la cotisation de l'UR Med pour 1 liasse :
-            - Assiette : Assiette de la cotisation CGSCOP
-            - Taux d’appel : 1/3 du taux
-            - Calcul intermédiaire : Assiette * taux
-                (soit 1/3 de la cotisation CGSCOP sans plancher)
-            - Complément de cotisation : 1% du résultat net si positif
-            - Abattement pour sociétariat :
-                Taux de sociétariat =   nombre de salariés sociétaires /
-                                        nombre de salariés
-                Abattement 20 % si >= 50 %
-                Abattement 30 % si >= 80 %
-            - Calcul cotisations :
-                [(Assiette*taux) + (résultat net *0.01)]* (1 ou 0.8 ou 0.7)
-
+           Calcule la cotisation CAE 1 partenaire :
+            - 0,4 % de la masse salariale annuelle brute
+            - plancher = 300
+            - plafond = 8500
             @return float : cotisation
         """
-        ur_med = self.env.ref('cgscop_partner.riga_14243')
         for liasse in self:
-            if liasse.partner_id.ur_id == ur_med:
-                # Assiette CG
-                assiette_rate = 1/3
-                assiette = liasse.contribution_cg
+            if liasse.partner_id.cae:
+                plancher = liasse.get_plancher_cotiz()['fede_cae']
+                plafond = 8500
+                rate = 0.004
+                contribution_cae = 0
+                if liasse.L2052_FY:
+                    contribution_cae = liasse.L2052_FY * rate
 
-                # Résultat net
-                net_results_rate = 0.01
-                net_results = liasse.L2053_HN if liasse.L2053_HN > 0 else liasse.L2051_DI
-                if liasse.dureeExercice and liasse.dureeExercice not in (0, 12):
-                    net_results = net_results * (12/liasse.dureeExercice)
-
-                # Effectifs
-                staff_id = self.get_last_staff_id(liasse.partner_id)
-                if staff_id:
-                    staff_shareholder_count = staff_id.staff_shareholder_count
-                    staff_count = staff_id.staff_count
+                if contribution_cae < plancher:
+                    liasse.contribution_cae = plancher
+                elif contribution_cae > plafond:
+                    liasse.contribution_cae = plafond
                 else:
-                    staff_shareholder_count = staff_count = 0
-
-                # Taux d'abattement pour sociétariat
-                if staff_count > 0:
-                    societariat_rate = staff_shareholder_count / staff_count
-                else:
-                    societariat_rate = 0
-
-                if 0.5 <= societariat_rate < 0.8:
-                    abatt_rate = 1 - 0.2
-                elif societariat_rate >= 0.8:
-                    abatt_rate = 1 - 0.3
-                else:
-                    abatt_rate = 1 - 0
-
-                # Calcul Cotisation
-                contribution_med = ((assiette * assiette_rate) +
-                         (net_results * net_results_rate)) * abatt_rate
-                final_contribution_med = contribution_med if contribution_med >= 0 else 0
-                liasse.contribution_med = final_contribution_med
+                    liasse.contribution_cae = contribution_cae
 
     # ------------------------------------------------------
     # Business Function
     # ------------------------------------------------------
+    def get_plancher_cotiz(self):
+        # Calculation plancher med
+        staff_id = self.get_last_staff_id(self.partner_id)
+        if staff_id:
+            staff_shareholder_count = staff_id.staff_shareholder_count
+            staff_count = staff_id.staff_count
+        else:
+            staff_shareholder_count = staff_count = 0
+        if staff_count > 0:
+            societariat_rate = staff_shareholder_count / staff_count
+        else:
+            societariat_rate = 0
+        if 0.5 <= societariat_rate < 0.8:
+            abatt_rate_med = 1 - 0.2
+        elif societariat_rate >= 0.8:
+            abatt_rate_med = 1 - 0.3
+        else:
+            abatt_rate_med = 1 - 0
+        assiette_rate_med = 1/3
+        plancher_cg = self.get_values_for_cotiz_cg(
+            self.partner_id)['plancher1']
+
+        return {
+            'fede_com': 108,
+            'fede_cae': 300,
+            'ur_med': plancher_cg * assiette_rate_med * abatt_rate_med,
+            'ur_hdf': 40,
+        }
+
     def get_values_for_cotiz_cg(self, partner):
         # Calcul des Taux SCOP en fonction du type
         plancher1 = 300
@@ -298,4 +361,4 @@ class ScopLiasseFiscale(models.Model):
         :return:
         """
         staff_id = partner.staff_ids.sorted(key=lambda l: l.effective_date)
-        return staff_id[-1] if len(staff_id) > 1 else staff_id
\ No newline at end of file
+        return staff_id[-1] if len(staff_id) > 1 else staff_id
diff --git a/report/__init__.py b/report/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..7b5fa1cac97787c466a30f5185a9cc5c65994f75
--- /dev/null
+++ b/report/__init__.py
@@ -0,0 +1,4 @@
+# © 2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from . import scop_contribution_report
diff --git a/report/scop_contribution_report.py b/report/scop_contribution_report.py
new file mode 100644
index 0000000000000000000000000000000000000000..2fed4b43a0ae60c723e3785a5d16feb752f58563
--- /dev/null
+++ b/report/scop_contribution_report.py
@@ -0,0 +1,44 @@
+# © 2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import models
+
+
+class ScopContributionReport(models.Model):
+    _inherit = "scop.contribution.report"
+
+    def _select_invoice(self):
+        select_str = super(ScopContributionReport, self)._select_invoice()
+        select_str = """
+            SELECT
+                CAST(i.year AS VARCHAR),
+                i.type_contribution_id,
+                i.partner_id,
+                SUM(i.amount_total_signed) AS amount_called,
+                SUM(i.amount_total_signed - i.residual_company_signed) AS amount_paid,
+                SUM(i.residual_company_signed) AS amount_due,
+                (
+                    CASE WHEN max(refund.id) IS NOT NULL THEN true ELSE FALSE END OR
+                    CASE WHEN max(refund_b.id) IS NOT NULL THEN true ELSE FALSE END
+                ) AS is_loss
+        """
+        return select_str
+
+    def _from_invoice(self):
+        from_str = super(ScopContributionReport, self)._from_invoice()
+        from_str += """
+            LEFT JOIN
+                scop_bordereau b ON i.bordereau_id = b.id
+            LEFT JOIN
+                scop_bordereau refund_b ON b.id = refund_b.refund_id
+        """
+        return from_str
+
+    def _where_invoice(self):
+        where_str = super(ScopContributionReport, self)._where_invoice()
+        where_str += "AND (i.bordereau_id IS NULL OR b.is_regul = false OR b.is_regul IS NULL)"
+        return where_str
+
+    # ------------------------------------------------------
+    # Computed fields
+    # ------------------------------------------------------
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
index 68bfdfbe3ce217b57d6aa7c62b09d3b8bf20a629..658ea35458a8044306a690cf97ee97080993a6c5 100755
--- a/security/ir.model.access.csv
+++ b/security/ir.model.access.csv
@@ -1,7 +1,11 @@
 id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_scop_cotisation_simulation,access_scop_cotisation_simulation,model_scop_cotisation_cg_simulation,account.group_account_manager,1,1,1,1
+access_scop_cotisation_simulation,access_scop_cotisation_simulation,model_scop_cotisation_cg_simulation,cgscop_cotisation_cg.group_cotisation_cg_administrative,1,1,1,1
 admin_access_scop_cotisation_simulation,admin_access_scop_cotisation_simulation,model_scop_cotisation_cg_simulation,cgscop_partner.group_cg_administrator,1,1,1,1
-access_scop_cotisation_cg,access_scop_cotisation_cg,model_scop_cotisation_cg,account.group_account_manager,1,1,1,0
+access_scop_cotisation_cg,access_scop_cotisation_cg,model_scop_cotisation_cg,cgscop_cotisation_cg.group_cotisation_cg_administrative,1,1,1,0
 admin_access_scop_cotisation_cg,admin_access_scop_cotisation_cg,model_scop_cotisation_cg,cgscop_partner.group_cg_administrator,1,1,1,1
-access_scop_bordereau,access_scop_bordereau,model_scop_bordereau,account.group_account_manager,1,1,1,1
+access_scop_bordereau,access_scop_bordereau,model_scop_bordereau,cgscop_cotisation_cg.group_cotisation_cg_administrative,1,1,1,1
 admin_access_scop_bordereau,admin_access_scop_bordereau,model_scop_bordereau,cgscop_partner.group_cg_administrator,1,1,1,1
+access_scop_bordereau_version,access_scop_bordereau_version,model_scop_bordereau_version,cgscop_cotisation_cg.group_cotisation_cg_administrative,1,1,1,1
+admin_access_scop_bordereau_version,admin_access_scop_bordereau_version,model_scop_bordereau_version,cgscop_partner.group_cg_administrator,1,1,1,1
+access_scop_bordereau_refund_wizard_quarter,access_scop_bordereau_refund_wizard_quarter,model_scop_bordereau_refund_wizard_quarter,cgscop_cotisation_cg.group_cotisation_cg_administrative,1,1,1,1
+admin_access_scop_bordereau_refund_wizard_quarter,admin_access_scop_bordereau_refund_wizard_quarter,model_scop_bordereau_refund_wizard_quarter,cgscop_partner.group_cg_administrator,1,1,1,1
diff --git a/security/security_rules.xml b/security/security_rules.xml
index c4cd9866467d0f777dd85cd267fd1080dc5a5ac4..a4f7a2f581cf2101a68e0cbb1fd3ebf96e4a448e 100644
--- a/security/security_rules.xml
+++ b/security/security_rules.xml
@@ -32,6 +32,7 @@
             <field name="perm_unlink" eval="True"/>
         </record>
 
+        <!-- Bordereaux only for own company -->
         <record id="cg_cotisation_cg_rule" model="ir.rule">
             <field name="name">Bordereaux consultables que pour sa société</field>
             <field name="model_id" ref="cgscop_cotisation_cg.model_scop_bordereau"/>
@@ -42,5 +43,27 @@
             <field name="perm_unlink" eval="True"/>
         </record>
 
+        <!-- Service Admin grant all access -->
+        <record id="scop_cotisation_cg_admin" model="ir.rule">
+            <field name="name">Cotisations - Modification  - Service Administratif</field>
+            <field name="model_id" ref="cgscop_cotisation_cg.model_scop_cotisation_cg"/>
+            <field name="domain_force">[(1,'=',1)]</field>
+            <field name="groups" eval="[(6, 0, [ref('group_cotisation_cg_administrative')])]"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_unlink" eval="True"/>
+        </record>
+        <record id="scop_bordereau_admin" model="ir.rule">
+            <field name="name">Bordereaux - Modification  - Service Administratif</field>
+            <field name="model_id" ref="cgscop_cotisation_cg.model_scop_bordereau"/>
+            <field name="domain_force">[(1,'=',1)]</field>
+            <field name="groups" eval="[(6, 0, [ref('group_cotisation_cg_administrative')])]"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_unlink" eval="True"/>
+        </record>
+
     </data>
 </odoo>
\ No newline at end of file
diff --git a/report/report_scop_bordereau.xml b/templates/report_scop_bordereau.xml
similarity index 97%
rename from report/report_scop_bordereau.xml
rename to templates/report_scop_bordereau.xml
index fc504bd551e1ad53ec4648553b773142b2404e5a..2457b564f0b6b858118cb91f5c5c1898611bb337 100644
--- a/report/report_scop_bordereau.xml
+++ b/templates/report_scop_bordereau.xml
@@ -46,15 +46,15 @@
                             <div></div>
                             <h5 class="mt8" style="font-weight: 600;">Cotisations annuelles</h5>
                             <p style="font-style: italic; font-size: 13px;">
-                                <t t-if="o.year_liasse_retenue">Calcul basé sur la liasse fiscale
+                                <t t-if="o.year_liasse">Calcul basé sur la liasse fiscale
                                     <t t-if="o.is_liasse_previ">
                                         <span>Prévisionnelle</span><br/>
                                     </t>
                                     <t t-else="">
-                                        <span t-esc="str(o.year_liasse_retenue)" /><br/>
+                                        <span t-esc="str(o.year_liasse)" /><br/>
                                     </t>
                                 </t>
-                                Assiette base <span t-field="o.type_assiette_retenu" /> : <span t-field="o.montant_assiette"  t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}" />.
+                                Assiette base <span t-field="o.type_assiette" /> : <span t-field="o.montant_assiette"  t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}" />.
                             </p>
                             <p>
                                 <t t-set="amount_line" t-value="o.get_contribution_type()" />
diff --git a/report/report_scop_bordereau_payments.xml b/templates/report_scop_bordereau_payments.xml
similarity index 89%
rename from report/report_scop_bordereau_payments.xml
rename to templates/report_scop_bordereau_payments.xml
index ef314818c92dbfc42c6b7c18b8e2043360fd844b..decf3acc3de24e28d68d99ae4fb92400745b86e6 100644
--- a/report/report_scop_bordereau_payments.xml
+++ b/templates/report_scop_bordereau_payments.xml
@@ -37,15 +37,15 @@
                             <div></div>
                             <h5 class="mt8" style="font-weight: 600;">Cotisations annuelles</h5>
                             <p style="font-style: italic; font-size: 13px;">
-                                <t t-if="o.year_liasse_retenue">Calcul basé sur la liasse fiscale
+                                <t t-if="o.year_liasse">Calcul basé sur la liasse fiscale
                                     <t t-if="o.is_liasse_previ">
                                         <span>Prévisionnelle</span><br/>
                                     </t>
                                     <t t-else="">
-                                        <span t-esc="str(o.year_liasse_retenue)" /><br/>
+                                        <span t-esc="str(o.year_liasse)" /><br/>
                                     </t>
                                 </t>
-                                Assiette base <span t-field="o.type_assiette_retenu" /> : <span t-field="o.montant_assiette"  t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}" />.
+                                Assiette base <span t-field="o.type_assiette" /> : <span t-field="o.montant_assiette"  t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}" />.
                             </p>
                             <p>
                                 <t t-set="amount_line" t-value="o.get_contribution_type()" />
@@ -76,12 +76,14 @@
                                     <tr>
                                         <th>Date d'échéance</th>
                                         <th class="text-right">Montant appelé</th>
-                                        <th class="text-right">Montant réglé</th>
+                                        <th class="text-right">Montant dû</th>
                                     </tr>
                                     <tr t-foreach="schedule_line.get('plan')" t-as="line" style="border-bottom: 1px solid #ccc;">
-                                        <td style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('date_maturity:day')"/></td>
-                                        <td class="text-right" style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('debit')" t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}"/></td>
-                                        <td class="text-right" style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('debit') - line.get('amount_residual')" t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}"/></td>
+                                        <t t-if="line.get('debit') > 0">
+                                            <td style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('date_maturity:day')"/></td>
+                                            <td class="text-right" style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('debit')" t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}"/></td>
+                                            <td class="text-right" style="border: none; background: inherit; color: inherit;"><t t-esc="line.get('amount_residual')" t-options="{'widget': 'monetary', 'display_currency': o.company_id.currency_id}"/></td>
+                                        </t>
                                     </tr>
                                 </table>
                                 <table class="table table-sm table-striped" style="border: none;">
diff --git a/report/report_scop_bordereau_refund.xml b/templates/report_scop_bordereau_refund.xml
similarity index 100%
rename from report/report_scop_bordereau_refund.xml
rename to templates/report_scop_bordereau_refund.xml
diff --git a/views/account_invoice.xml b/views/account_invoice.xml
index 93531d0b5c03b6d931bafb76c401edde2e79260d..0c0150510081e0efb1f5033d705c7fb1d6343f23 100644
--- a/views/account_invoice.xml
+++ b/views/account_invoice.xml
@@ -12,11 +12,14 @@
 
                 <xpath expr="//header/button[@name='action_invoice_open']" position="attributes">
                     <attribute name="states"/>
-                    <attribute name="attrs">{'invisible':['|', ('type','=','out_invoice'), ('state','!=','draft')]}</attribute>
+                    <attribute name="invisible">1</attribute>
                 </xpath>
                 <xpath expr="//header/button[@name='preview_invoice']" position="attributes">
                     <attribute name="invisible">True</attribute>
                 </xpath>
+                <xpath expr="//header/button[@name='%(account.action_account_invoice_refund)d']" position="attributes">
+                    <attribute name="invisible">True</attribute>
+                </xpath>
 
                 <xpath expr="//field[@name='liasse_fiscale_id']" position="replace">
                     <group>
@@ -25,8 +28,7 @@
                     </group>
                     <group>
                         <field name="amount_cg_calculated" readonly="1"/>
-                        <field name="nb_quarter" readonly="1"/>
-                        <field name="amount_cg_prorata" readonly="1"/>
+                        <field name="cotiz_quarter" readonly="1"/>
                     </group>
                 </xpath>
 
@@ -35,11 +37,7 @@
                 </xpath>
 
                 <xpath expr="//field[@name='payment_term_id']" position="attributes">
-                    <attribute name="attrs">{'invisible':[('state','=','draft')]}</attribute>
-                </xpath>
-
-                <xpath expr="//field[@name='date_invoice']" position="attributes">
-                    <attribute name="attrs">{'invisible':[('state','=','draft')]}</attribute>
+                    <attribute name="invisible">1</attribute>
                 </xpath>
 
                 <xpath expr="//field[@name='date_due']" position="attributes">
@@ -93,12 +91,5 @@
             <field name="act_window_id" ref="action_scop_cg_appel_cotisation"/>
         </record>
 
-        <!-- MENUS -->
-        <menuitem id="menu_scop_cotisation_cg_appel_cotisation"
-                  name="Appels de cotisations"
-                  parent="cgscop_cotisation.menu_scop_cotisation"
-                  action="action_scop_cg_appel_cotisation"
-                  sequence="20"/>
-
     </data>
 </odoo>
\ No newline at end of file
diff --git a/views/menus.xml b/views/menus.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cf83ae6744ce629cd8ef5fcbb472b79e762df853
--- /dev/null
+++ b/views/menus.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!-- Copyright 2019 Le Filament
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
+
+<odoo>
+    <data>
+        <!-- MENUS -->
+        <menuitem id="menu_scop_cotisation_cg_main"
+                  parent="cgscop_cotisation.menu_scop_cotisation"
+                  name="Gestion des cotisations CG Scop"
+                  groups="cgscop_cotisation_cg.group_cotisation_cg_administrative"
+                  sequence="10"/>
+        <menuitem id="menu_scop_cotisation_cg_calcul"
+                  name="Campagnes de cotisations"
+                  parent="cgscop_cotisation_cg.menu_scop_cotisation_cg_main"
+                  groups="cgscop_cotisation_cg.group_cotisation_cg_administrative"
+                  action="action_scop_cotisation_cg"
+                  sequence="10"/>
+        <menuitem name="Bordereaux"
+                  id="scop_bordereau_menu"
+                  parent="cgscop_cotisation_cg.menu_scop_cotisation_cg_main"
+                  groups="cgscop_cotisation_cg.group_cotisation_cg_administrative"
+                  action="scop_bordereau_act_window"
+                  sequence="20"/>
+        <menuitem id="menu_scop_cotisation_cg_appel_cotisation"
+                  name="Appels de cotisations"
+                  parent="cgscop_cotisation_cg.menu_scop_cotisation_cg_main"
+                  groups="cgscop_cotisation_cg.group_cotisation_cg_administrative"
+                  action="action_scop_cg_appel_cotisation"
+                  sequence="30"/>
+    </data>
+</odoo>
diff --git a/views/scop_bordereau_cg.xml b/views/scop_bordereau_cg.xml
index 3b5fe37db7c19366d1b88c6cd8bbf6d98503175d..2b3bc49fed20d0010d4b995882efc61af22be1a5 100644
--- a/views/scop_bordereau_cg.xml
+++ b/views/scop_bordereau_cg.xml
@@ -12,15 +12,25 @@
                 <form create="false" string="Bordereaux">
                     <header>
                         <field name="state" widget="statusbar" clickable="False" readonly="True"/>
-                        <button name="validate_bordereau" class="oe_highlight" string="Valider le bordereau" type="object" states="new" confirm="Confirmer la validation du bordereau ?"/>
+                        <button name="validate_bordereau" class="oe_highlight" string="Valider le bordereau" type="object"
+                                states="new" confirm="Confirmer la validation du bordereau ?"/>
                         <button name="print_bordereau" string="Imprimer" type="object" states="validated,paid"/>
                         <button name="action_send_email" string="Envoyer par mail" type="object" states="validated"/>
-                        <button name="update_cotiz_and_lines" class="btn-info" string="Mettre à jour les cotisations" type="object" states="new"/>
+                        <button name="validate_ongoing_bordereau" class="oe_highlight" string="Valider cette nouvelle version" type="object" states="ongoing"/>
+                        <button name="cancel_ongoing_bordereau" class="oe_highlight" string="Annuler cette nouvelle version" type="object" states="ongoing"/>
+                        <button name="action_change_payment_mode"
+                                class="btn-info" string="Changer le mode de paiement"
+                                type="object" states="ongoing,validated"/>
                         <button name="%(cgscop_cotisation_cg.scop_cotisation_regul_wizard_act_window)d"
                                 class="btn-warning"
                                 string="Effectuer une Régularisation"
                                 type="action"
                                 states="validated,paid"/>
+                        <button name="%(cgscop_cotisation_cg.scop_bordereau_refund_wizard_act_window)d"
+                                class="btn-warning"
+                                string="Ajouter un avoir"
+                                type="action"
+                                states="ongoing,validated,paid"/>
                         <button name="%(cgscop_bordereau_report_refund)d"
                                 class="btn-info"
                                 string="Imprimer l'avoir"
@@ -29,10 +39,19 @@
                     </header>
                     <sheet>
                         <div class="oe_button_box" name="button_box">
+                            <button name="action_show_liasse" type="object"
+                                    class="oe_stat_button" icon="fa-bar-chart-o"
+                                    attrs="{'invisible':[('liasse_count','=',0)]}">
+                                <field string="Liasses" name="liasse_count" widget="statinfo"/>
+                            </button>
+                            <button name="action_show_cotiz" type="object"
+                                    class="oe_stat_button" icon="fa-pencil-square-o"
+                                    attrs="{'invisible':[('invoice_count','=',0)]}">
+                                <field string="Appels" name="invoice_count" widget="statinfo"/>
+                            </button>
                             <button class="oe_stat_button" name="open_payment"
                                     string="Paiements en cours" type="object"
-                                    attrs="{'invisible':['|', ('move_reconciled','=',True), ('state', '!=', 'validated')]}" icon="fa-university"/>
-                            <field name="move_reconciled" invisible="1"/>
+                                    attrs="{'invisible':['|', ('has_outstanding','=',False), ('state', '!=', 'validated')]}" icon="fa-university"/>
                         </div>
                         <div class="oe_title">
                             <h1>
@@ -43,98 +62,98 @@
                             Adhérent : <field name="partner_id"/> <br/>
                             UR : <field name="partner_ur_id" readonly="True" options="{'no_open': True}"/>
                         </h4>
+                        <field name="has_outstanding" invisible="1"/>
+                        <div class="alert alert-info mt-3" role="alert"
+                             attrs="{'invisible': ['|', ('has_outstanding','=',False), ('state', '!=', 'validated')]}">
+                            Vous avez des paiements en circulation pour ce bordereau.
+                        </div>
+                        <div class="alert alert-warning" role="alert" attrs="{'invisible': [('state', '!=', 'ongoing')]}">
+                            <strong>Bordereau en cours de modification </strong>(Détails dans l'onglet "Historique")<br/>
+                        </div>
                         <field name="is_regul" invisible="1"/>
                         <div class="alert alert-warning" role="alert" attrs="{'invisible': [('is_regul', '!=', True)]}">
                             <strong>Bordereau annulé le : </strong><field name="date_regul" readonly="True"/><br/>
                             <strong>Motif : </strong><field name="comment_regul" readonly="True"/><br/>
                             <strong>Nouveau bordereau : </strong><field name="refund_id" readonly="True"/>
                         </div>
+                        <div class="alert alert-warning" role="alert" attrs="{'invisible': ['|', ('is_regul', '=', True), ('comment_regul', '=', False)]}">
+                            <strong>Bordereau version <field name="version" readonly="1"/></strong><br/>
+                            <strong>Modifié le : </strong><field name="date_regul" readonly="True"/><br/>
+                            <strong>Motif : </strong><field name="comment_regul" readonly="True"/><br/>
+                        </div>
                         <group>
                             <group>
                                 <field name="base_cotisation_cg"/>
                                 <field name="date_cotisation" attrs="{'readonly':[('state','!=','new')]}"/>
-                                <field name="payment_term_id" attrs="{'readonly':[('state','!=','new')]}"/>
                                 <field name="payment_mode_id" attrs="{'readonly':[('state','!=','new')]}"/>
-                                <field name="liasse_fiscale_id"/>
-                                <field name="type_liasse_fiscale" options="{'no_open': True}"/>
+                                <hr/>
+                                <field name="nb_quarter" attrs="{'readonly':[('state','!=','new')]}"/>
+                                <button name="update_bordereau_with_liasse" class="btn" string="Recalculer le bordereau"
+                                        confirm="Recalculer les valeurs du bordereau en fonction de la liasse et du nombre de trimestres ?" type="object" states="new"/>
                             </group>
                             <group>
-                                <field name="year_liasse_retenue" attrs="{'readonly':[('state','!=','new')]}"/>
-                                <field name="type_assiette_retenu"/>
-                                <field name="montant_assiette"/>
+                                <span class="oe_grey" attrs="{'invisible': [('liasse_fiscale_id', '!=', False)]}">Pas de liasse fiscale pour le calcul</span>
+                                <field name="liasse_fiscale_id" attrs="{'invisible': [('liasse_fiscale_id', '=', False)]}"/>
+                                <field name="year_liasse" attrs="{'invisible': [('liasse_fiscale_id', '=', False)]}"/>
+                                <field name="type_liasse_fiscale" options="{'no_open': True}" attrs="{'invisible': [('liasse_fiscale_id', '=', False)]}"/>
+                                <button name="action_change_liasse"
+                                        class="btn-info mb5"
+                                        string="Changer de liasse fiscale"
+                                        type="object"
+                                        states="new"/>
+                                <br/>
+                                <hr/>
+                                <field name="type_assiette" attrs="{'invisible': [('liasse_fiscale_id', '=', False)]}"/>
+                                <field name="montant_assiette" attrs="{'invisible': [('liasse_fiscale_id', '=', False)]}"/>
                                 <field name="amount_total_cotiz"/>
-                                <field name="dureeExercice"/>
-                                <field name="nb_quarter" attrs="{'readonly':[('state','!=','new')]}"/>
+                                <field name="details" nolabel="1"/>
                             </group>
-                            <hr/>
-                            <field name="invoice_ids" widget="one2many">
-                                <tree edit="false" create="false" delete="false">
-                                    <field name="type_contribution_id"/>
-                                    <field name="date_invoice"/>
-                                    <field name="name"/>
-                                    <field name="amount_total_signed" string="Montant total" sum="Total"/>
-                                    <field name="residual_signed" string="Montant dû" sum="Total"/>
-                                    <field name="state"/>
-                                    <button name="view_cotiz" string="Afficher" type="object" icon="fa-pencil-square-o"/>
-                                </tree>
-                                <form>
-                                    <group>
+                        </group>
+
+                        <notebook>
+                            <page string="Appels de cotisation">
+                                <field name="invoice_ids" widget="one2many" class="mt-2">
+                                    <tree edit="false" create="false" delete="false" default_order="type_contribution_id, cotiz_quarter"
+                                          decoration-info="state == 'draft'" decoration-success="state == 'paid'"
+                                          decoration-muted="state == 'cancel'" decoration-danger="type == 'out_refund' and state == 'open'">
+                                        <field name="type" invisible="1"/>
                                         <field name="type_contribution_id"/>
-                                        <field name="date_invoice"/>
+                                        <field name="cotiz_quarter"/>
+                                        <field name="date_due"/>
                                         <field name="name"/>
-                                        <field name="amount_cg_calculated"/>
-                                        <field name="amount_total_signed"/>
-                                        <field name="residual_signed"/>
-                                        <field name="nb_quarter" />
+                                        <field name="amount_total_signed" string="Montant total" sum="Total"/>
+                                        <field name="residual_signed" string="Montant dû" sum="Total"/>
                                         <field name="state"/>
-                                    </group>
-                                </form>
-                            </field>
-                        </group>
-                        <notebook>
-                            <page string="Cotisation CG Scop">
-                                <group col="2">
-                                    <group string="Données liasse fiscale">
-                                        <field name="type_assiette_connu"/>
-                                        <field name="ca_connu"/>
-                                        <field name="va_connu"/>
-                                    </group>
-                                    <group string="Données pour le calcul">
-                                        <field name="type_assiette_retenu"/>
-                                        <field name="ca_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="va_cg_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                    </group>
-                                </group>
-                            </page>
-                            <page string="Cotisation Fédé de la com">
-                                <group col="2">
-                                    <group string="Données liasse fiscale">
-                                        <field name="va_connu"/>
-                                        <field name="staff_average_connu"/>
-                                        <field name="staff_count_connu"/>
-                                    </group>
-                                    <group string="Données pour le calcul">
-                                        <field name="va_fede_com_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="staff_average_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="staff_fede_com_count_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                    </group>
-                                </group>
+                                        <button name="view_cotiz" string="Afficher" type="object" icon="fa-pencil-square-o"/>
+                                    </tree>
+                                    <form>
+                                        <group>
+                                            <field name="type_contribution_id"/>
+                                            <field name="cotiz_quarter"/>
+                                            <field name="date_due"/>
+                                            <field name="name"/>
+                                            <field name="amount_cg_calculated"/>
+                                            <field name="amount_total_signed"/>
+                                            <field name="residual_signed"/>
+                                            <field name="nb_quarter" />
+                                            <field name="state"/>
+                                        </group>
+                                    </form>
+                                </field>
                             </page>
-                            <page string="Cotisation UR">
-                                <group col="2">
-                                    <group string="Données liasse fiscale">
-                                        <field name="net_results_connu"/>
-                                        <field name="staff_shareholder_count_connu"/>
-                                        <field name="staff_count_connu"/>
-                                        <field name="wage_cg_connu"/>
-                                    </group>
-                                    <group string="Données pour le calcul">
-                                        <field name="net_results_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="staff_shareholder_count_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="staff_ur_med_count_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                        <field name="wage_cg_retenu" attrs="{'readonly':[('state','!=','new')]}"/>
-                                    </group>
-                                </group>
+                            <page string="Historique">
+                                <field name="bordereau_version_ids" widget="one2many" class="mt-2">
+                                    <tree create="false" delete="false" default_order="version desc" editable="top">
+                                        <field name="date"/>
+                                        <field name="version"/>
+                                        <field name="comment" attrs="{'readonly':[('state','=','validated')]}"/>
+                                        <field name="liasse_fiscale_id_old"/>
+                                        <field name="type_assiette"/>
+                                        <field name="montant_assiette"/>
+                                        <field name="amount_total_cotiz"/>
+                                        <field name="state" widget="label_selection"/>
+                                    </tree>
+                                </field>
                             </page>
                         </notebook>
                     </sheet>
@@ -157,7 +176,7 @@
                     <field name="partner_ur_id"/>
                     <field name="year"/>
                     <field name="state"/>
-                    <field name="type_assiette_retenu"/>
+                    <field name="type_assiette"/>
                     <field name="montant_assiette"/>
                     <field name="amount_total_cotiz" sum="Total"/>
                     <field name="amount_residual" sum="Total"/>
@@ -177,10 +196,14 @@
                     <field name="year" string="Année de cotisation"/>
                     <filter name="state_new" string="Brouillon"
                             domain="[('state', '=', 'new')]"/>
+                    <filter name="state_ongoing" string="En cours de modification"
+                            domain="[('state', '=', 'ongoing')]"/>
                     <filter name="state_validated" string="Validé"
                             domain="[('state', '=', 'validated')]"/>
                     <filter name="state_paid" string="Payé"
                             domain="[('state', '=', 'paid')]"/>
+                    <filter name="has_outstanding" string="Paiements en cours"
+                            domain="[('has_outstanding', '=', True)]"/>
                     <separator/>
                     <filter name="current_year" string="Campagne année en cours"
                             domain="[('year', '=', (context_today()).strftime('%Y'))]"/>
@@ -189,9 +212,9 @@
                     <filter name="next_year" string="Campagne année suivante"
                             domain="[('year', '=', (context_today()+datetime.timedelta(weeks=52)).strftime('%Y'))]"/>
                     <separator/>
-                    <filter name="bordereau_equal_zero" string="Cotisation(s) égale(s) à zéro"
-                            domain="[('amount_total_cotiz', '=', 0)]"/>
-                    <filter name="assiette_equal_zero" string="Assiette(s) égale(s) à zéro"
+                    <filter name="bordereau_without_liasse" string="Pas de liasse de référence"
+                            domain="[('liasse_fiscale_id', '=', False)]"/>
+                    <filter name="assiette_equals_zero" string="Assiette(s) égale(s) à zéro"
                             domain="[('montant_assiette', '=', 0)]"/>
                     <separator/>
                     <filter name="4_quarter" string="Sur 4 trimestres" domain="[('nb_quarter', '=', '4')]"/>
@@ -199,8 +222,8 @@
                     <filter name="2_quarter" string="Sur 2 trimestres" domain="[('nb_quarter', '=', '2')]"/>
                     <filter name="1_quarter" string="Sur 1 trimestre" domain="[('nb_quarter', '=', '1')]"/>
                     <separator/>
-                    <filter name="is_ca" string="Assiette CA" domain="[('type_assiette_retenu', '=', 'ca')]"/>
-                    <filter name="is_va" string="Assiette VA" domain="[('type_assiette_retenu', '=', 'va')]"/>
+                    <filter name="is_ca" string="Assiette CA" domain="[('type_assiette', '=', 'ca')]"/>
+                    <filter name="is_va" string="Assiette VA" domain="[('type_assiette', '=', 'va')]"/>
                     <group string="Group By">
                         <filter name="by_year" string="Année de cotisation" context="{'group_by':'year'}"/>
                     </group>
@@ -210,19 +233,12 @@
 
         <!-- Action -->
         <record id="scop_bordereau_act_window" model="ir.actions.act_window">
-            <field name="name">Bodereaux</field>
+            <field name="name">Bordereaux</field>
             <field name="type">ir.actions.act_window</field>
             <field name="res_model">scop.bordereau</field>
             <field name="view_mode">tree,form</field>
             <field name="context">{'search_default_current_year': 1}</field>
         </record>
 
-        <!-- Menu -->
-        <menuitem name="Bordereaux"
-                  id="scop_bordereau_menu"
-                  parent="cgscop_cotisation.menu_scop_cotisation"
-                  action="scop_bordereau_act_window"
-                  sequence="30"/>
-
     </data>
 </odoo>
\ No newline at end of file
diff --git a/views/scop_cotisation_cg.xml b/views/scop_cotisation_cg.xml
index 16fdaa47725a247d7773411ede0c4d978c59cba3..cead779d9a90cf06c42c96b83fe29ead09f74f41 100644
--- a/views/scop_cotisation_cg.xml
+++ b/views/scop_cotisation_cg.xml
@@ -44,7 +44,6 @@
                                 <field name="date_cotisation" attrs="{'readonly': [('state', '!=', 'new')], 'required': [('state', '!=', 'new')]}"/>
                                 <field name="create_date"/>
                                 <field name="write_date"/>
-                                <field name="payment_term_id"/>
                             </group>
                             <group name="count_contribution" string="Adhérents">
                                 <field name="member_count" readonly="1"/>
@@ -156,11 +155,5 @@
             <field name="help">Affiche les bases de calcul des cotisations</field>
         </record>
 
-
-        <!-- MENUS -->
-        <menuitem id="menu_scop_cotisation_cg_calcul"
-                  parent="cgscop_cotisation.menu_scop_cotisation"
-                  action="action_scop_cotisation_cg"
-                  sequence="10"/>
     </data>
 </odoo>
diff --git a/views/scop_liasse_fiscale.xml b/views/scop_liasse_fiscale.xml
index 2f5260ea5c31affedcb7e9f3ff0faad1a6a7b363..c9556bfa0e116c32c3e88156cf663dbc2e1cc850 100644
--- a/views/scop_liasse_fiscale.xml
+++ b/views/scop_liasse_fiscale.xml
@@ -27,6 +27,7 @@
                             <field name="contribution_hdf" string="Cotisation HDF"/>
                             <field name="contribution_med" string="Cotisation Méditerranée"/>
                             <field name="contribution_com" string="Cotisation Fédération Com"/>
+                            <field name="contribution_cae" string="Cotisation Fédération CAE"/>
                         </group>
                     </group>
                 </xpath>
diff --git a/wizard/__init__.py b/wizard/__init__.py
index 909809b470b208bb2bf6c457cdac1fea10011631..a23c4c181537020603c1172196a3bd075001c6b0 100644
--- a/wizard/__init__.py
+++ b/wizard/__init__.py
@@ -3,6 +3,9 @@
 
 from . import account_invoice_refund
 from . import export_journal_wizard
+from . import scop_bordereau_update_liasse_wizard
+from . import scop_bordereau_payment_mode_wizard
+from . import scop_bordereau_refund_wizard
 from . import scop_bordereau_update_confirm
 from . import scop_bordereau_validate_confirm
 from . import scop_cotisation_cg_regul
diff --git a/wizard/scop_bordereau_payment_mode_wizard.py b/wizard/scop_bordereau_payment_mode_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..45efe0ab20b24c13e42fc35a59855c52e588cedf
--- /dev/null
+++ b/wizard/scop_bordereau_payment_mode_wizard.py
@@ -0,0 +1,58 @@
+# Copyright 2021 Le Filament
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models, api
+
+
+class ScopBordereauChangePaymentMode(models.TransientModel):
+    _name = 'scop.bordereau.change.payment.mode.wizard'
+    _description = 'Changement de mode de paiement'
+
+    bordereau_id = fields.Many2one(
+        comodel_name='scop.bordereau',
+        string='Bordereau',
+        readonly=True,
+    )
+    payment_mode_id = fields.Many2one(
+        comodel_name='account.payment.mode',
+        string="Nouveau mode de paiment",)
+    change_type = fields.Selection(
+        string='Type d\'affectation',
+        selection=[('punctual', 'Définir pour les échéances non payées de ce '
+                                'bordereau uniquement'),
+                   ('all', 'Définir pour toutes les prochaines échéances')],
+        default='punctual',
+        required=False, )
+
+    # ------------------------------------------------------
+    # Action Button
+    # ------------------------------------------------------
+    def action_change_payment_mode(self):
+        bordereau_id = self.bordereau_id
+        # Link new liasse fiscale to bordereau
+        if self.change_type == 'all':
+            bordereau_id.partner_id.update({
+                'customer_payment_mode_id': self.payment_mode_id.id,
+            })
+        bordereau_id.update({
+            'payment_mode_id': self.payment_mode_id.id,
+        })
+        bordereau_id.invoice_ids.update({
+            'payment_mode_id': self.payment_mode_id.id,
+        })
+        contrib_cg_journal = self.env.user.company_id.contribution_journal_id
+        contrib_ur_fede_journal = \
+            self.env.user.company_id.contribution_ur_or_fede_journal_id
+        move_line_ids = self.env['account.move.line'].search([
+            ('partner_id', '=', self.bordereau_id.partner_id.id),
+            ('journal_id', 'in', (
+                contrib_cg_journal.id, contrib_ur_fede_journal.id)),
+            ('full_reconcile_id', '=', False),
+            ('balance', '!=', 0),
+            ('account_id.reconcile', '=', True),
+            ('account_id.internal_type', '=', 'receivable')
+        ])
+        move_line_ids.update({
+            'payment_mode_id': self.payment_mode_id.id,
+        })
+        return {'type': 'ir.actions.act_window_close'}
diff --git a/wizard/scop_bordereau_payment_mode_wizard.xml b/wizard/scop_bordereau_payment_mode_wizard.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4af8d77fe44f19aefa6aac02dae0c207c42122f6
--- /dev/null
+++ b/wizard/scop_bordereau_payment_mode_wizard.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <!--  Copyright 2021 Le Filament
+          License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).  -->
+    <data>
+
+        <record id="scop_bordereau_change_payment_mode_wizard_form_view" model="ir.ui.view">
+            <field name="name">scop.bordereau.change.payment.mode.wizard.form</field>
+            <field name="model">scop.bordereau.change.payment.mode.wizard</field>
+            <field name="arch" type="xml">
+                <form string="Changement de mode de paiement">
+                    <group>
+                        <field name="payment_mode_id" options="{'no_open': True, 'no_create': True}"/>
+                        <field name="change_type" widget="radio" nolabel="1" class="mt-4"/>
+                    </group>
+                    <footer>
+                        <button name="action_change_payment_mode" string="Ok" type="object" default_focus="1" class="oe_highlight"/>
+                        <button class="oe_highlight" string="Annuler" special="cancel"/>
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+    </data>
+</odoo>
\ No newline at end of file
diff --git a/wizard/scop_bordereau_refund_wizard.py b/wizard/scop_bordereau_refund_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..53614d19218f20135ec17c2e5150aeb6b42ed92e
--- /dev/null
+++ b/wizard/scop_bordereau_refund_wizard.py
@@ -0,0 +1,200 @@
+# Copyright 2021 Le Filament
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models, api
+from odoo.exceptions import ValidationError, UserError
+
+
+class ScopBordereauRefundWizard(models.TransientModel):
+    _name = 'scop.bordereau.refund.wizard'
+    _description = 'Avoir sur les bordereaux'
+
+    bordereau_id = fields.Many2one(
+        comodel_name='scop.bordereau',
+        string='Bordereau',
+        readonly=True,
+    )
+    date_refund = fields.Date(
+        string="Date de régularisation",
+        default=fields.Date.today(), required=1)
+    cotiz_reminder = fields.Html('Rappel des cotisations', readonly=1)
+    amount_refund = fields.Float('Montant (par trimestre)', required=1)
+    comment = fields.Char('Motif de l\'avoir', required=1)
+    type_cotiz = fields.Selection(
+        string='Type de cotisation',
+        selection=lambda self: self._selection_type_cotiz(),
+        required=1)
+    quarter_ids = fields.Many2many(
+        relation='scop_bordereau_refund_wizard_quarter_rel',
+        comodel_name='scop.bordereau.refund.wizard.quarter',
+        string='Trimestres')
+
+    # ------------------------------------------------------
+    # Constrains
+    # ------------------------------------------------------
+    @api.constrains('date_refund')
+    def _check_date_refund(self):
+        last_date = max(self.bordereau_id.invoice_ids.mapped('date_invoice'))
+        if self.date_refund > fields.Date.today() or \
+                self.date_refund < last_date:
+            raise ValidationError("La date de l'avoir doit être "
+                                  "inférieure ou égale à la date du jour et "
+                                  "supérieure à la dernière date de "
+                                  "facturation liée au bordereau.")
+
+    # ------------------------------------------------------
+    # Override ORM
+    # ------------------------------------------------------
+    @api.model
+    def default_get(self, fields):
+        res = super(ScopBordereauRefundWizard, self).default_get(fields)
+        bordereau_id = self.env['scop.bordereau'].browse(
+            self.env.context.get('active_id')
+        )
+        res.update({
+            'bordereau_id': bordereau_id.id,
+            'cotiz_reminder': bordereau_id.details,
+        })
+        return res
+
+    @api.model
+    def _selection_type_cotiz(self):
+        bordereau_id = self.env['scop.bordereau'].browse(
+            self.env.context.get('active_id')
+        )
+
+        contribs = bordereau_id.invoice_ids.read_group(
+            [('id', 'in', bordereau_id.invoice_ids.ids)],
+            ['type_contribution_id', 'amount_total_signed'],
+            ['type_contribution_id'])
+
+        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
+        if bordereau_id.partner_id.ur_id.id == ur_hdf:
+            product_ur = self.env.user.company_id.contribution_hdf_id
+        else:  # ur = ur_med
+            product_ur = self.env.user.company_id.contribution_med_id
+
+        cotiz_type = {
+            self.env.ref('cgscop_partner.riga_14397').id:
+                self.env.user.company_id.contribution_cg_id,
+            self.env.ref('cgscop_partner.riga_14398').id:
+                self.env.user.company_id.contribution_fede_com_id,
+            self.env.ref('cgscop_partner.cotiz_fede_cae').id:
+                self.env.user.company_id.contribution_fede_cae_id,
+            self.env.ref('cgscop_partner.riga_14399').id:
+                product_ur,
+        }
+
+        type_cotiz_select_i = list()
+        type_cotiz_select_list = list()
+        for contrib in contribs:
+            type_cotiz = contrib.get('type_contribution_id')[0]
+            if type_cotiz not in type_cotiz_select_i:
+                type_cotiz_select_i.append(type_cotiz)
+                type_cotiz_select_list.append(
+                    (type_cotiz, cotiz_type[type_cotiz].name))
+        return type_cotiz_select_list
+
+    # ------------------------------------------------------
+    # Action
+    # ------------------------------------------------------
+    def create_refund(self):
+        """
+        Create refund
+        """
+        if len(self.quarter_ids) == 0:
+            raise UserError('Vous devez sélectionner au moins un trimestre.')
+        if self.amount_refund <= 0:
+            raise UserError('Le montant de l\'avoir doit être supérieur à 0.')
+        if not self.type_cotiz:
+            raise UserError('Vous devez sélectionner un type de cotisation.')
+        bordereau_id = self.bordereau_id
+        partner_id = bordereau_id.partner_id
+        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
+
+        # CREATE VERSION
+        bordereau_id.read(['amount_total_cotiz'])
+        ongoing_version = bordereau_id.bordereau_version_ids.filtered(
+            lambda v: v.version == bordereau_id.version and v.state == 'new'
+        )
+        if not ongoing_version:
+            self.env['scop.bordereau.version'].create({
+                'bordereau_id': bordereau_id.id,
+                'date': self.date_refund,
+                'comment': self.comment,
+                'version': bordereau_id.version,
+                'liasse_fiscale_id_old': bordereau_id.liasse_fiscale_id.id,
+                'type_assiette': bordereau_id.type_assiette,
+                'montant_assiette': bordereau_id.montant_assiette,
+                'amount_total_cotiz': bordereau_id.amount_total_cotiz,
+            })
+
+        # CREATE REFUND
+        if partner_id.ur_id.id == ur_hdf:
+            product_ur = self.env.user.company_id.contribution_hdf_id
+            account_ur = self.env.user.company_id.receivable_account_ur_hdf_id
+        else:  # ur = ur_med
+            product_ur = self.env.user.company_id.contribution_med_id
+            account_ur = self.env.user.company_id.receivable_account_ur_med_id
+
+        cotiz_type = {
+            self.env.ref('cgscop_partner.riga_14397').id:
+                [self.env.user.company_id.contribution_cg_id,
+                 self.env.user.company_id.contribution_journal_id,
+                 partner_id.property_account_receivable_id],
+            self.env.ref('cgscop_partner.riga_14398').id:
+                [self.env.user.company_id.contribution_fede_com_id,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 self.env.user.company_id.receivable_account_fede_com_id],
+            self.env.ref('cgscop_partner.cotiz_fede_cae').id:
+                [self.env.user.company_id.contribution_fede_cae_id,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 self.env.user.company_id.receivable_account_fede_cae_id],
+            self.env.ref('cgscop_partner.riga_14399').id:
+                [product_ur,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 account_ur],
+        }
+        product = cotiz_type.get(int(self.type_cotiz))[0]
+
+        for quarter_id in self.quarter_ids:
+            refund = self.env['account.invoice'].create({
+                'partner_id': partner_id.id,
+                'journal_id': cotiz_type.get(int(self.type_cotiz))[1].id,
+                'account_id': cotiz_type.get(int(self.type_cotiz))[2].id,
+                'type': 'out_refund',
+                'date_invoice': self.date_refund,
+                'date': self.date_refund,
+                'state': 'draft',
+                'number': False,
+                'origin': bordereau_id.name,
+                'name': self.comment,
+                'bordereau_id': bordereau_id.id,
+                'is_contribution': True,
+                'year': bordereau_id.year,
+                'cotiz_quarter': quarter_id.quarter,
+                'liasse_fiscale_id': bordereau_id.liasse_fiscale_id.id,
+                'type_contribution_id': self.type_cotiz,
+                'payment_mode_id': bordereau_id.payment_mode_id.id,
+                'date_due': self.date_refund,
+            })
+            self.env['account.invoice.line'].create({
+                'name': self.comment,
+                'invoice_id': refund.id,
+                'product_id': product.id,
+                'account_id': product.property_account_income_id.id,
+                'price_unit': self.amount_refund
+            })
+
+
+class ScopBordereauRefundWizardQuarer(models.Model):
+    _name = 'scop.bordereau.refund.wizard.quarter'
+    _description = 'Trimestres pour échéance de cotisation'
+
+    name = fields.Char('Nom', compute='_compute_name')
+    quarter = fields.Integer('Trismestre', required=1)
+
+    @api.multi
+    def _compute_name(self):
+        for r in self:
+            r.name = str(r.quarter)
diff --git a/wizard/scop_bordereau_refund_wizard.xml b/wizard/scop_bordereau_refund_wizard.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e42f5c0268bb3f78a2a2faeb20aead211ea6b5c8
--- /dev/null
+++ b/wizard/scop_bordereau_refund_wizard.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <!--  Copyright 2021 Le Filament
+          License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).  -->
+    <data>
+
+        <record id="scop_bordereau_refund_wizard_form_view" model="ir.ui.view">
+            <field name="name">scop.bordereau.refund.wizard.form</field>
+            <field name="model">scop.bordereau.refund.wizard</field>
+            <field name="arch" type="xml">
+                <form string="Générer un avoir">
+                    <sheet>
+                        <group>
+                            <field name="cotiz_reminder"/>
+                            <hr/>
+                            <field name="type_cotiz"/>
+                            <field name="date_refund"/>
+                            <separator/>
+                            <field name="amount_refund"/>
+                            <field name="quarter_ids" widget="many2many_checkboxes"/>
+                            <field name="comment"/>
+                        </group>
+                    </sheet>
+                    <footer>
+                        <button name="create_refund" type="object"  string="Créer l'avoir" class="oe_highlight"/>
+                        <button string="Annuler" special="cancel" class="oe_link"/>
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+        <record id="scop_bordereau_refund_wizard_act_window" model="ir.actions.act_window">
+            <field name="name">Avoir sur le bordereau</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">scop.bordereau.refund.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</odoo>
\ No newline at end of file
diff --git a/wizard/scop_bordereau_update_confirm.py b/wizard/scop_bordereau_update_confirm.py
index 0779da108029618241dd39281f1fbc23f5dd1dce..d14e35b55aae3103f33a53f7e3c5e89f5e607790 100644
--- a/wizard/scop_bordereau_update_confirm.py
+++ b/wizard/scop_bordereau_update_confirm.py
@@ -22,5 +22,5 @@ class ScopBordereauUpdate(models.TransientModel):
             if record.state != 'new':
                 raise UserError(_("Impossible de mettre à jour un bordereau "
                                   "qui n'est pas à l'état de brouillon"))
-            record.update_cotiz_and_lines()
+            record.create_cotiz_and_lines()
         return {'type': 'ir.actions.act_window_close'}
diff --git a/wizard/scop_bordereau_update_liasse_wizard.py b/wizard/scop_bordereau_update_liasse_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd0ed6a8e3b00af425a11a042bfc0a1100ee1759
--- /dev/null
+++ b/wizard/scop_bordereau_update_liasse_wizard.py
@@ -0,0 +1,162 @@
+# Copyright 2021 Le Filament
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models, api
+from odoo.exceptions import UserError
+
+
+class ScopBordereauChangeLiasse(models.TransientModel):
+    _name = 'scop.bordereau.change.liasse.wizard'
+    _description = 'Changement de liasse sur le bordereau'
+
+    bordereau_id = fields.Many2one(
+        comodel_name='scop.bordereau',
+        string='Bordereau',
+        readonly=True,
+    )
+    partner_id = fields.Many2one(
+        related='bordereau_id.partner_id'
+    )
+    company_currency_id = fields.Many2one(
+        related='bordereau_id.company_currency_id')
+
+    # Ancienne liasse
+    liasse_fiscale_id = fields.Many2one(
+        related='bordereau_id.liasse_fiscale_id'
+    )
+    amount_total_cotiz = fields.Monetary(
+        related='bordereau_id.amount_total_cotiz',
+        currency_field='company_currency_id'
+    )
+    amount_cg = fields.Float(
+        'Cotisation CG Scop actuelle', compute='_compute_amount_cotiz')
+    amount_ur_med = fields.Float(
+        'Cotisation UR Med actuelle', compute='_compute_amount_cotiz')
+    amount_ur_hdf = fields.Float(
+        'Cotisation UR HDF actuelle', compute='_compute_amount_cotiz')
+    amount_fede_com = fields.Float(
+        'Cotisation Fede Com actuelle', compute='_compute_amount_cotiz')
+    amount_fede_cae = fields.Float(
+        'Cotisation Fede CAE actuelle', compute='_compute_amount_cotiz')
+    type_assiette = fields.Selection(
+        string='Type d\'assiette',
+        related='bordereau_id.type_assiette',)
+    montant_assiette = fields.Integer(
+        string='Montant de l\'assiette',
+        related='bordereau_id.montant_assiette')
+    ca = fields.Float(
+        related='bordereau_id.ca')
+    va = fields.Float(
+        related='bordereau_id.va')
+    net_results = fields.Float(
+        related='bordereau_id.net_results')
+    wage_cg = fields.Float(
+        related='bordereau_id.wage_cg')
+
+    # Nouvelle liasse
+    liasse_fiscale_new_id = fields.Many2one(
+        comodel_name='scop.liasse.fiscale',
+        string='Nouvelle liasse Fiscale',
+    )
+    amount_total_cotiz_new = fields.Monetary(
+        string='Nouveau montant total de(s) cotisation(s)',
+        currency_field='company_currency_id',
+        readonly=1)
+    type_id_new = fields.Selection(
+        'Type de liasse', related='liasse_fiscale_new_id.type_id')
+    source_new = fields.Selection(
+        'Source de la liasse', related='liasse_fiscale_new_id.source')
+    amount_cg_new = fields.Float(
+        'Cotisation CG Scop',
+        related='liasse_fiscale_new_id.contribution_cg')
+    amount_ur_med_new = fields.Float(
+        'Cotisation UR Méditerranée',
+        related='liasse_fiscale_new_id.contribution_med')
+    amount_ur_hdf_new = fields.Float(
+        'Cotisation UR HDF',
+        related='liasse_fiscale_new_id.contribution_hdf')
+    amount_fede_com_new = fields.Float(
+        'Cotisation Fédé Communication',
+        related='liasse_fiscale_new_id.contribution_com')
+    amount_fede_cae_new = fields.Float(
+        'Cotisation Fédé CAE',
+        related='liasse_fiscale_new_id.contribution_cae')
+    type_assiette_new = fields.Selection(
+        related='liasse_fiscale_new_id.contribution_base_type')
+    montant_assiette_new = fields.Integer(
+        related='liasse_fiscale_new_id.contribution_base_amount')
+    # ca_new = fields.Float(
+    #     related='liasse_fiscale_new_id.av_cg')
+    # va_new = fields.Float(
+    #     string='VA', compute='_compute_liasse_new_values')
+    # net_results_new = fields.Float(
+    #     string='Résultat net', compute='_compute_liasse_new_values')
+    # wage_cg_new = fields.Float(
+    #     string='Montant masse salariale', compute='_compute_liasse_new_values')
+
+    # ------------------------------------------------------
+    # Compute
+    # ------------------------------------------------------
+    def _compute_amount_cotiz(self):
+        type_cotisation_cg = self.env.ref('cgscop_partner.riga_14397').id
+        type_cotisation_fede_com = self.env.ref('cgscop_partner.riga_14398').id
+        type_cotisation_fede_cae = self.env.ref(
+            'cgscop_partner.cotiz_fede_cae').id
+        type_cotisation_ur = self.env.ref('cgscop_partner.riga_14399').id
+        for r in self:
+            partner = r.bordereau_id.partner_id
+            cotiz = r.bordereau_id.invoice_ids
+            # CG
+            cotiz_cg = cotiz.filtered(
+                lambda i: i.type_contribution_id.id == type_cotisation_cg
+            )
+            r.amount_cg = sum(cotiz_cg.mapped('amount_total'))
+            # Fede Com
+            cotiz_fede_com = cotiz.filtered(
+                lambda i: i.type_contribution_id.id == type_cotisation_fede_com
+            )
+            r.amount_fede_com = sum(cotiz_fede_com.mapped('amount_total'))
+            # Fede CAE
+            cotiz_fede_cae = cotiz.filtered(
+                lambda i: i.type_contribution_id.id == type_cotisation_fede_cae
+            )
+            r.amount_fede_cae = sum(cotiz_fede_cae.mapped('amount_total'))
+            # UR HDF
+            ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
+            if partner.ur_id.id == ur_hdf:
+                cotiz_ur_hdf = cotiz.filtered(
+                    lambda i: i.type_contribution_id.id == type_cotisation_ur
+                )
+                r.amount_ur_hdf = sum(cotiz_ur_hdf.mapped('amount_total'))
+            # UR Med
+            ur_med = self.env.ref('cgscop_partner.riga_14243').id
+            if partner.ur_id.id == ur_med:
+                cotiz_ur_med = cotiz.filtered(
+                    lambda i: i.type_contribution_id.id == type_cotisation_ur
+                )
+                r.amount_ur_med = sum(cotiz_ur_med.mapped('amount_total'))
+
+    # ------------------------------------------------------
+    # Onchange
+    # ------------------------------------------------------
+    @api.onchange('liasse_fiscale_new_id')
+    def _compute_liasse_new_values(self):
+        for r in self:
+            if r.liasse_fiscale_new_id:
+                r.amount_total_cotiz_new = \
+                    r.amount_cg_new + r.amount_ur_hdf_new + \
+                    r.amount_ur_med_new + r.amount_fede_com
+
+    # ------------------------------------------------------
+    # Action Button
+    # ------------------------------------------------------
+    def update_liasse_fiscale(self):
+        bordereau_id = self.bordereau_id
+        if not self.liasse_fiscale_new_id:
+            raise UserError('Merci de choisir une nouvelle liasse fiscale.')
+        # Link new liasse fiscale to bordereau
+        bordereau_id.update({
+            'liasse_fiscale_id': self.liasse_fiscale_new_id,
+        })
+        bordereau_id.create_cotiz_and_lines()
+        return {'type': 'ir.actions.act_window_close'}
diff --git a/wizard/scop_bordereau_update_liasse_wizard.xml b/wizard/scop_bordereau_update_liasse_wizard.xml
new file mode 100644
index 0000000000000000000000000000000000000000..610d83f7e9506e2d10f870c89c5f857890d92a4d
--- /dev/null
+++ b/wizard/scop_bordereau_update_liasse_wizard.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <!--  Copyright 2021 Le Filament
+          License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).  -->
+    <data>
+
+        <record id="scop_bordereau_change_liasse_wizard_form_view" model="ir.ui.view">
+            <field name="name">scop.bordereau.change.liasse.wizard.form</field>
+            <field name="model">scop.bordereau.change.liasse.wizard</field>
+            <field name="arch" type="xml">
+                <form string="Changement de liasse">
+                    <sheet>
+                        <div class="row">
+                            <div class="col-6">
+                                <group string="Données initiales" class="text-muted">
+                                    <field name="liasse_fiscale_id" options='{"no_open": True}'/>
+                                    <hr/>
+                                    <field name="amount_total_cotiz"/>
+                                    <field name="amount_cg"/>
+                                    <field name="amount_ur_med" attrs="{'invisible':[('amount_ur_med','=',0)]}"/>
+                                    <field name="amount_ur_hdf" attrs="{'invisible':[('amount_ur_hdf','=',0)]}"/>
+                                    <field name="amount_fede_com" attrs="{'invisible':[('amount_fede_com','=',0)]}"/>
+                                    <field name="amount_fede_cae" attrs="{'invisible':[('amount_fede_cae','=',0)]}"/>
+                                    <hr/>
+                                    <field name="type_assiette"/>
+                                    <field name="montant_assiette"/>
+                                    <hr/>
+                                    <field name="ca"/>
+                                    <field name="va"/>
+                                    <field name="net_results"/>
+                                    <field name="wage_cg"/>
+                                </group>
+                            </div>
+                            <div class="col-6">
+                                <group>
+                                    <field name="partner_id" invisible="1"/>
+                                    <field name="liasse_fiscale_new_id" options='{"no_open": True, "no_create":True}'
+                                           domain="[('partner_id', '=', partner_id),
+                                                    ('is_qualified', '=', True),
+                                                    ('id', '!=', liasse_fiscale_id)]"/>
+                                    <field name="type_id_new" attrs="{'invisible':[('liasse_fiscale_new_id','=',False)]}"/>
+                                    <field name="source_new" attrs="{'invisible':[('liasse_fiscale_new_id','=',False)]}"/>
+                                </group>
+                                <group string="Nouveaux calculs (Sans arrondi)" attrs="{'invisible':[('liasse_fiscale_new_id','=',False)]}">
+                                    <field name="amount_total_cotiz_new"/>
+                                    <field name="amount_cg_new"/>
+                                    <field name="amount_ur_med_new" attrs="{'invisible':[('amount_ur_med_new','=',0)]}"/>
+                                    <field name="amount_ur_hdf_new" attrs="{'invisible':[('amount_ur_hdf_new','=',0)]}"/>
+                                    <field name="amount_fede_com_new" attrs="{'invisible':[('amount_fede_com_new','=',0)]}"/>
+                                    <field name="amount_fede_cae_new" attrs="{'invisible':[('amount_fede_cae_new','=',0)]}"/>
+                                    <hr/>
+                                    <field name="type_assiette_new"/>
+                                    <field name="montant_assiette_new"/>
+                                    <hr/>
+                                </group>
+                            </div>
+                        </div>
+                    </sheet>
+                    <footer>
+                        <button name="update_liasse_fiscale" type="object"  string="Modifier la liasse" class="oe_highlight" confirm="Confirmer le changement de liasse"/>
+                        <button string="Annuler" special="cancel" class="oe_link"/>
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+        <record id="scop_bordereau_change_liasse_wizard_act_window" model="ir.actions.act_window">
+            <field name="name">Changement liasse bordereau</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">scop.bordereau.change.liasse.wizard</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</odoo>
\ No newline at end of file
diff --git a/wizard/scop_cotisation_cg_regul.py b/wizard/scop_cotisation_cg_regul.py
index 4bc8d4b26ee753594feb8d6bc2417387dafc6660..5f0d6d7a1dc2e469d852148e0399481887e93daa 100644
--- a/wizard/scop_cotisation_cg_regul.py
+++ b/wizard/scop_cotisation_cg_regul.py
@@ -2,7 +2,8 @@
 # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
 
 from odoo import fields, models, api
-from odoo.exceptions import UserError
+from odoo.exceptions import UserError, ValidationError
+
 
 class ScopCotisationRegul(models.TransientModel):
     _name = 'scop.cotisation.regul.wizard'
@@ -22,17 +23,15 @@ class ScopCotisationRegul(models.TransientModel):
         string='Adhérent',
         readonly=True,
     )
+
+    # Old liasse
     liasse_fiscale_id = fields.Many2one(
         comodel_name='scop.liasse.fiscale',
-        string='Liasse Fiscale',
-    )
-    liasse_fiscale_new_id = fields.Many2one(
-        comodel_name='scop.liasse.fiscale',
-        string='Liasse Fiscale',
+        string='Liasse Fiscale de référence',
     )
     year = fields.Integer('Année de la liasse')
     type_assiette_retenu = fields.Selection(
-        string='Type assiette de retenu',
+        string='Type assiette',
         selection=[('ca', 'CA'),
                    ('va', 'VA'), ],
     )
@@ -42,21 +41,46 @@ class ScopCotisationRegul(models.TransientModel):
         string='Montant total de(s) cotisation(s)')
     detail = fields.Text('Détail cotisation')
     comment = fields.Char('Motif de régularisation')
-    type_assiette_retenu_new = fields.Selection(
-        string='Nouvelle assiette de retenu',
-        selection=[('ca', 'CA'),
-                   ('va', 'VA'), ],
+
+    # New liasse
+    liasse_fiscale_new_id = fields.Many2one(
+        comodel_name='scop.liasse.fiscale',
+        string='Liasse Fiscale',
     )
-    ca_new = fields.Float('Montant CA')
-    va_new = fields.Float('Montant VA')
-    wage_cg_new = fields.Float('Masse Salariale')
-    amount_cg = fields.Float('Cotisation CG Scop')
-    amount_ur_med = fields.Float('Cotisation UR Méditerranée')
-    amount_ur_hdf = fields.Float('Cotisation UR HDF')
-    amount_fede_com = fields.Float('Cotisation Fédé Communication')
-    amount_fede_cae = fields.Float('Cotisation Fédé CAE')
+    type_id_new = fields.Selection(
+        string='Type de liasse', related='liasse_fiscale_new_id.type_id')
+    source_new = fields.Selection(
+        string='Source de la liasse', related='liasse_fiscale_new_id.source')
+    type_assiette_new = fields.Selection(
+        related='liasse_fiscale_new_id.contribution_base_type')
+    montant_assiette_new = fields.Integer(
+        related='liasse_fiscale_new_id.contribution_base_amount')
+    amount_cg = fields.Float(
+        related='liasse_fiscale_new_id.contribution_cg')
+    amount_ur_med = fields.Float(
+        related='liasse_fiscale_new_id.contribution_med')
+    amount_ur_hdf = fields.Float(
+        related='liasse_fiscale_new_id.contribution_hdf')
+    amount_fede_com = fields.Float(
+        related='liasse_fiscale_new_id.contribution_com')
+    amount_fede_cae = fields.Float(
+        related='liasse_fiscale_new_id.contribution_cae')
+
     is_payment = fields.Boolean('Paiements liés')
 
+    # ------------------------------------------------------
+    # Constrains
+    # ------------------------------------------------------
+    @api.constrains('date_regul')
+    def _check_date_regul(self):
+        last_date = max(self.bordereau_id.invoice_ids.mapped('date_invoice'))
+        if self.date_regul > fields.Date.today() or \
+                self.date_regul < last_date:
+            raise ValidationError("La date de régulation doit être "
+                                  "inférieure ou égale à la date du jour et "
+                                  "supérieure à la dernière date de "
+                                  "facturation liée au bordereau.")
+
     # ------------------------------------------------------
     # Override ORM
     # ------------------------------------------------------
@@ -67,7 +91,7 @@ class ScopCotisationRegul(models.TransientModel):
             self.env.context.get('active_id')
         )
         contribs = bordereau_id.invoice_ids.read_group(
-            [('id', 'in',bordereau_id.invoice_ids.ids)],
+            [('id', 'in', bordereau_id.invoice_ids.ids)],
             ['type_contribution_id', 'amount_total_signed'],
             ['type_contribution_id'])
         detail = "<table class='o_group o_inner_group'>"
@@ -88,8 +112,8 @@ class ScopCotisationRegul(models.TransientModel):
             'bordereau_id': bordereau_id.id,
             'partner_id': bordereau_id.partner_id.id,
             'liasse_fiscale_id': bordereau_id.liasse_fiscale_id.id,
-            'year': bordereau_id.year_liasse_retenue,
-            'type_assiette_retenu': bordereau_id.type_assiette_retenu,
+            'year': bordereau_id.year_liasse,
+            'type_assiette_retenu': bordereau_id.type_assiette,
             'montant_assiette': bordereau_id.montant_assiette,
             'amount_total_cotiz': bordereau_id.amount_total_cotiz,
             'detail': detail,
@@ -98,150 +122,127 @@ class ScopCotisationRegul(models.TransientModel):
         return res
 
     # ------------------------------------------------------
-    # Button function
+    # Action
     # ------------------------------------------------------
-    def get_new_contribution(self):
-        partner = self.partner_id
-        liasse = self.liasse_fiscale_new_id
-        # Duplicate bordereau to use in function
-        new_bdx = self.bordereau_id.copy(default={'state': 'new'})
-        va = new_bdx.base_cotisation_cg.get_va(liasse)
-        new_bdx.update({
-            'liasse_fiscale_id': liasse.id,
-            'ca_retenu': liasse.revenue_cgsubv,
-            'va_fede_com_retenu': va,
-            'va_cg_retenu': va,
-            'wage_cg_retenu': liasse.wage_cg,
-            'state': 'new',
-        })
-        # Get variables
-        new_bdx._compute_type_assiette_retenu()
-        self.type_assiette_retenu_new = new_bdx.type_assiette_retenu
-        self.ca_new = new_bdx.ca_retenu
-        self.va_new = new_bdx.va_cg_retenu
-        self.wage_cg_new = new_bdx.wage_cg_retenu
-
-        # Calcul CG Scop
-        amount_cg = new_bdx.base_cotisation_cg.round_to_closest_multiple(
-            new_bdx.base_cotisation_cg.get_cotiz_cg(partner, new_bdx), 4)
-        self.amount_cg = amount_cg
-
-        # Calcul Fede Com
-        if partner.is_federation_com:
-            amount_fede_com = new_bdx.base_cotisation_cg.round_to_closest_multiple(
-                new_bdx.base_cotisation_cg.get_cotiz_fede_com(new_bdx), 4)
-            self.amount_fede_com = amount_fede_com
-
-        # Calcul Fede CAE
-        if partner.cae:
-            amount_fede_cae = new_bdx.base_cotisation_cg.round_to_closest_multiple(
-                new_bdx.base_cotisation_cg.get_cotiz_fede_cae(), 4)
-            self.amount_fede_cae = amount_fede_cae
-
-        # Calcul UR HDF
-        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
-        if partner.ur_id.id == ur_hdf:
-            amount_ur_hdf = new_bdx.base_cotisation_cg.round_to_closest_multiple(
-                new_bdx.base_cotisation_cg.get_cotiz_hdf(new_bdx), 4)
-            self.amount_ur_hdf = amount_ur_hdf
-
-        # Calcul UR Mediterranee
-        ur_med = self.env.ref('cgscop_partner.riga_14243').id
-        if partner.ur_id.id == ur_med:
-            amount_ur_med = new_bdx.base_cotisation_cg.round_to_closest_multiple(
-                new_bdx.base_cotisation_cg.get_cotiz_med(
-                    self.amount_cg, new_bdx), 4)
-            self.amount_ur_med = amount_ur_med
-
-        # Unlink bordereau
-        new_bdx.state = 'new'
-        new_bdx.sudo().unlink()
-        # Return Action
-        action = {
-            'name': 'Régularisation Cotisation',
-            'type': 'ir.actions.act_window',
-            'res_model': 'scop.cotisation.regul.wizard',
-            'view_mode': 'form',
-            'target': 'new',
-            'res_id': self.id,
-            'context': self._context,
-        }
-        return action
-
     def update_contribution(self):
         if not self.comment:
-            raise UserError(
-                "Vous devez renseigner un motif de régularisation pour valider.")
+            raise UserError("Vous devez renseigner un motif de "
+                            "régularisation pour valider.")
 
         bordereau_id = self.bordereau_id
+        partner_id = bordereau_id.partner_id
 
-        # Refunds creation
-        for invoice in bordereau_id.invoice_ids:
-            # Remove reconcile payments if exists
-            if invoice.payment_move_line_ids:
-                invoice.payment_move_line_ids.remove_move_reconcile()
-            # Create refund
-            refund = invoice.refund(
-                date_invoice=self.date_regul,
-                date=self.date_regul,
-                description=self.comment,
-                journal_id=invoice.journal_id.id,
-            )
-            # Update refund
-            refund.update({
-                'bordereau_id': self.bordereau_id,
-                'is_contribution': True,
-                'year': invoice.year,
-                'liasse_fiscale_id': invoice.liasse_fiscale_id,
-                'type_contribution_id': invoice.type_contribution_id,
-                'payment_term_id': invoice.payment_term_id,
-                'payment_mode_id': invoice.payment_mode_id,
-            })
-            # Reconcile lines
-            movelines = invoice.move_id.line_ids
-            to_reconcile_ids = {}
-            to_reconcile_lines = self.env['account.move.line']
-            for line in movelines:
-                if line.account_id.id == invoice.account_id.id:
-                    to_reconcile_lines += line
-                    to_reconcile_ids.setdefault(line.account_id.id, []).append(
-                        line.id)
-                if line.reconciled:
-                    line.remove_move_reconcile()
-            refund.action_invoice_open()
-            for tmpline in refund.move_id.line_ids:
-                if tmpline.account_id.id == invoice.account_id.id:
-                    to_reconcile_lines += tmpline
-            to_reconcile_lines.filtered(
-                lambda l: l.reconciled == False).reconcile()
-
-        # Create new bordereau
-        new_bordereau = bordereau_id.base_cotisation_cg.create_bordereau(
-            member=self.partner_id,
-            nb_quarter=bordereau_id.nb_quarter,
-            liasse=self.liasse_fiscale_new_id,
-            date=self.date_regul,
-            is_regul=True
-        )
-        new_bordereau.update({
-            'name': bordereau_id.name[0:10] + '-' + str(bordereau_id.version + 1),
-            'version': bordereau_id.version + 1,
+        # CREATE VERSION
+        bordereau_id.read(['amount_total_cotiz'])
+        self.env['scop.bordereau.version'].create({
+            'bordereau_id': bordereau_id.id,
+            'date': self.date_regul,
+            'comment': self.comment,
+            'version': bordereau_id.version,
+            'liasse_fiscale_id_old': bordereau_id.liasse_fiscale_id.id,
+            'type_assiette': bordereau_id.type_assiette,
+            'montant_assiette': bordereau_id.montant_assiette,
+            'amount_total_cotiz': bordereau_id.amount_total_cotiz,
         })
-        new_bordereau.base_cotisation_cg.create_cotiz_and_lines(
-            bordereau=new_bordereau, date=self.date_regul, is_regul=True)
-        # Link new to old bordereau
+
+        # CREATE REGUL
+        contribs = bordereau_id.invoice_ids.read_group(
+            [('id', 'in', bordereau_id.invoice_ids.ids)],
+            ['type_contribution_id', 'amount_total_signed'],
+            ['type_contribution_id'])
+
+        ur_hdf = self.env.ref('cgscop_partner.riga_14232').id
+        if partner_id.ur_id.id == ur_hdf:
+            amount_ur = self.amount_ur_hdf
+            product_ur = self.env.user.company_id.contribution_hdf_id
+            account_ur = self.env.user.company_id.receivable_account_ur_hdf_id
+        else:  # ur = ur_med
+            amount_ur = self.amount_ur_med
+            product_ur = self.env.user.company_id.contribution_med_id
+            account_ur = self.env.user.company_id.receivable_account_ur_med_id
+
+        cotiz_type = {
+            self.env.ref('cgscop_partner.riga_14397').id:
+                [self.amount_cg,
+                 self.env.user.company_id.contribution_cg_id,
+                 self.env.user.company_id.contribution_journal_id,
+                 partner_id.property_account_receivable_id.id],
+            self.env.ref('cgscop_partner.riga_14398').id:
+                [self.amount_fede_com,
+                 self.env.user.company_id.contribution_fede_com_id,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 self.env.user.company_id.receivable_account_fede_com_id],
+            self.env.ref('cgscop_partner.cotiz_fede_cae').id:
+                [self.amount_fede_cae,
+                 self.env.user.company_id.contribution_fede_cae_id,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 self.env.user.company_id.receivable_account_fede_cae_id],
+            self.env.ref('cgscop_partner.riga_14399').id:
+                [amount_ur,
+                 product_ur,
+                 self.env.user.company_id.contribution_ur_or_fede_journal_id,
+                 account_ur],
+        }
+
+        quarters = [bordereau_id.base_cotisation_cg.trimester_1,
+                    bordereau_id.base_cotisation_cg.trimester_2,
+                    bordereau_id.base_cotisation_cg.trimester_3,
+                    bordereau_id.base_cotisation_cg.trimester_4]
+
+        for contrib in contribs:
+            type_cotiz = contrib.get('type_contribution_id')[0]
+            amount_cotiz_old = contrib.get('amount_total_signed')
+            amount_cotiz = cotiz_type.get(type_cotiz)[0]
+            refund_amount_total = self.env['scop.cotisation'].\
+                round_to_closest_multiple(amount_cotiz_old - amount_cotiz, 4)
+            product = cotiz_type.get(type_cotiz)[1]
+            type_invoice = False
+
+            if refund_amount_total < 0:
+                type_invoice = 'out_invoice'
+                refund_amount_total *= -1
+            elif refund_amount_total > 0:
+                type_invoice = 'out_refund'
+            refund_amount = refund_amount_total / bordereau_id.nb_quarter
+
+            if type_invoice:
+                for i in range(0, bordereau_id.nb_quarter):
+
+                    if self.date_regul < quarters[i]:
+                        date_due = quarters[i]
+                    else:
+                        date_due = self.date_regul
+
+                    refund = self.env['account.invoice'].create({
+                        'partner_id': partner_id.id,
+                        'journal_id': cotiz_type.get(type_cotiz)[2].id,
+                        'account_id': partner_id.property_account_receivable_id.id,
+                        'type': type_invoice,
+                        'date_invoice': self.date_regul,
+                        'date': self.date_regul,
+                        'state': 'draft',
+                        'number': False,
+                        'origin': bordereau_id.name,
+                        'name': self.comment,
+                        'bordereau_id': bordereau_id.id,
+                        'is_contribution': True,
+                        'year': bordereau_id.year,
+                        'liasse_fiscale_id': bordereau_id.liasse_fiscale_id.id,
+                        'type_contribution_id': type_cotiz,
+                        'payment_mode_id': bordereau_id.payment_mode_id.id,
+                        'date_due': date_due,
+                        'cotiz_quarter': i+1,
+                    })
+                    self.env['account.invoice.line'].create({
+                        'name': self.comment + " - " + str(i+1) + "/" + str(bordereau_id.nb_quarter),
+                        'invoice_id': refund.id,
+                        'product_id': product.id,
+                        'account_id': product.property_account_income_id.id,
+                        'price_unit': refund_amount
+                    })
         bordereau_id.update({
-            'refund_id': new_bordereau.id,
-            'is_regul': True,
-            'date_regul': self.date_regul,
-            'comment_regul': self.comment,
-            'state': 'cancel',
+            'liasse_fiscale_id': self.liasse_fiscale_new_id.id
+        })
+        bordereau_id.invoice_ids.update({
+            'liasse_fiscale_id': self.liasse_fiscale_new_id.id
         })
-        # Return Action
-        action = {
-            'type': 'ir.actions.act_window',
-            'res_model': 'scop.bordereau',
-            'view_mode': 'form',
-            'res_id': new_bordereau.id,
-        }
-        return action
diff --git a/wizard/scop_cotisation_cg_regul_wizard.xml b/wizard/scop_cotisation_cg_regul_wizard.xml
index 76065d5cd599b343dbf820f1cb2a8c75ab2fab9b..b4a258d27a081f18307278a82d31e235820b3e26 100644
--- a/wizard/scop_cotisation_cg_regul_wizard.xml
+++ b/wizard/scop_cotisation_cg_regul_wizard.xml
@@ -25,13 +25,6 @@
                                 </h3>
                             </div>
                         </div>
-                        <div class="row" attrs="{'invisible': [('is_payment', '=', False)]}" >
-                            <div class="col-12">
-                                <div class="alert alert-danger" role="alert">
-                                    Attention, des paiements sont liés aux appels de cotisation de ce bordereau. La régularisation entrainera le "délettrage" de ces paiements qui seront à rapprocher avec le nouveau bordereau émis.
-                                </div>
-                            </div>
-                        </div>
                         <div class="row">
                             <div class="col-6">
                                 <group string="Données initiales" class="text-muted">
@@ -47,14 +40,16 @@
                                 <group string="Nouveaux calculs">
                                     <field name="date_regul" required="1"/>
                                     <separator/>
-                                    <field name="liasse_fiscale_new_id" domain="[('partner_id', '=', partner_id)]" options='{"no_create": True}' help="Nouvelle liasse fiscale à prendre en compte"/>
+                                    <field name="liasse_fiscale_new_id" domain="[('partner_id', '=', partner_id)]"
+                                           options='{"no_create": True}' help="Nouvelle liasse fiscale à prendre en compte"/>
+                                </group>
+                                <group>
+                                    <field name="type_id_new" attrs="{'invisible': [('liasse_fiscale_new_id', '=', False)]}"/>
+                                    <field name="source_new" attrs="{'invisible': [('liasse_fiscale_new_id', '=', False)]}"/>
                                 </group>
-                                    <button name="get_new_contribution" type="object" string="Nouveau Calcul" class="btn-info"/>
                                 <group>
-                                    <field name="type_assiette_retenu_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
-                                    <field name="ca_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
-                                    <field name="va_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
-                                    <field name="wage_cg_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
+                                    <field name="type_assiette_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
+                                    <field name="montant_assiette_new" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
                                 </group>
                                 <group>
                                     <field name="amount_cg" attrs="{'invisible': [('amount_cg', '=', 0.0)]}" readonly="1"/>
@@ -69,7 +64,7 @@
                         </div>
                     </sheet>
                     <footer>
-                        <button name="update_contribution" type="object"  string="Régulariser le bordereau" class="oe_highlight" confirm="Confirmer la validation de la régularisation"/>
+                        <button name="update_contribution" type="object"  string="Régulariser le bordereau" class="oe_highlight"/>
                         <button string="Annuler" special="cancel" class="oe_link"/>
                     </footer>
                 </form>
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 "