diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4acca684ec8c5cda7b3ecd21b9e568ab03d57e8c..3efb4d9157dc36d84e372eec5fc21e7f4a417a58 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -12,11 +12,15 @@ exclude: |
   /static/(src/)?lib/|
   # Repos using Sphinx to generate docs don't need prettying
   ^docs/_templates/.*\.html$|
+  # Don't bother non-technical authors with formatting issues in docs
+  readme/.*\.(rst|md)$|
+  # Ignore build and dist directories in addons
+  /build/|/dist/|
   # You don't usually want a bot to modify your legal texts
   (LICENSE.*|COPYING.*)
 default_language_version:
   python: python3
-  node: "14.13.0"
+  node: "16.17.0"
 repos:
   - repo: local
     hooks:
@@ -33,40 +37,38 @@ repos:
         language: fail
         files: '[a-zA-Z0-9_]*/i18n/en\.po$'
   - repo: https://github.com/oca/maintainer-tools
-    rev: ab1d7f6
+    rev: f71041f22b8cd68cf7c77b73a14ca8d8cd190a60
     hooks:
       # update the NOT INSTALLABLE ADDONS section above
       - id: oca-update-pre-commit-excluded-addons
       - id: oca-fix-manifest-website
         args: ["https://le-filament.com"]
-  - repo: https://github.com/myint/autoflake
-    rev: v1.4
-    hooks:
-      - id: autoflake
+      - id: oca-gen-addon-readme
         args:
-          - --expand-star-imports
-          - --ignore-init-module-imports
-          - --in-place
-          - --remove-all-unused-imports
-          - --remove-duplicate-keys
-          - --remove-unused-variables
-  - repo: https://github.com/psf/black
-    rev: 22.3.0
+          - --addons-dir=.
+          - --branch=16.0
+          - --org-name=lefilament
+          - --repo-name=template_module
+          - --if-source-changed
+          - --keep-source-digest
+  - repo: https://github.com/OCA/odoo-pre-commit-hooks
+    rev: v0.0.25
     hooks:
-      - id: black
+      - id: oca-checks-odoo-module
+      - id: oca-checks-po
   - repo: https://github.com/pre-commit/mirrors-prettier
-    rev: v2.1.2
+    rev: v2.7.1
     hooks:
       - id: prettier
         name: prettier (with plugin-xml)
         additional_dependencies:
-          - "prettier@2.1.2"
-          - "@prettier/plugin-xml@0.12.0"
+          - "prettier@2.7.1"
+          - "@prettier/plugin-xml@2.2.0"
         args:
           - --plugin=@prettier/plugin-xml
         files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$
   - repo: https://github.com/pre-commit/mirrors-eslint
-    rev: v7.8.1
+    rev: v8.24.0
     hooks:
       - id: eslint
         verbose: true
@@ -74,7 +76,7 @@ repos:
           - --color
           - --fix
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v3.2.0
+    rev: v4.3.0
     hooks:
       - id: trailing-whitespace
         # exclude autogenerated files
@@ -95,27 +97,14 @@ repos:
       - id: check-xml
       - id: mixed-line-ending
         args: ["--fix=lf"]
-  - repo: https://github.com/asottile/pyupgrade
-    rev: v2.7.2
-    hooks:
-      - id: pyupgrade
-        args: ["--keep-percent-format"]
-  - repo: https://github.com/PyCQA/isort
-    rev: 5.12.0
-    hooks:
-      - id: isort
-        name: isort except __init__.py
-        args:
-          - --settings=.
-        exclude: /__init__\.py$
-  - repo: https://github.com/PyCQA/flake8
-    rev: 3.8.3
+  - repo: https://github.com/astral-sh/ruff-pre-commit
+    rev: v0.1.3
     hooks:
-      - id: flake8
-        name: flake8
-        additional_dependencies: ["flake8-bugbear==20.1.4"]
+      - id: ruff
+        args: [--fix, --exit-non-zero-on-fix]
+      - id: ruff-format
   - repo: https://github.com/OCA/pylint-odoo
-    rev: 7.0.2
+    rev: v8.0.19
     hooks:
       - id: pylint_odoo
         name: pylint with optional checks
diff --git a/models/acc_operation.py b/models/acc_operation.py
index b42e3c35de0196e88140124f83dbfff53354f31c..f4e80f0500179f2494ca5020e1afb396c7bd7ac1 100644
--- a/models/acc_operation.py
+++ b/models/acc_operation.py
@@ -1,11 +1,13 @@
 # Copyright 2023 Le Filament (<http://www.le-filament.com>)
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
-from datetime import datetime
+from datetime import datetime, time
 
 from dateutil.relativedelta import relativedelta
+
 from odoo import _, models
 from odoo.exceptions import ValidationError
+from odoo.osv import expression
 from odoo.tools import date_utils
 
 DEFAULT_MONTH_RANGE = 3
@@ -17,7 +19,7 @@ class AccOperation(models.Model):
     # ------------------------------------------------------
     # Actions
     # ------------------------------------------------------
-    def action_view_courbes(self):
+    def action_view_curves(self):
         """
         Action qui ouvre le portail sur l'opération
         :return: Vue Qweb
@@ -33,7 +35,7 @@ class AccOperation(models.Model):
     # ------------------------------------------------------
     # Business methods
     # ------------------------------------------------------
-    def get_power_tot(self):
+    def get_last_month_power_tot(self):
         """
         Fonction retournant la consommation totale, l'autoconsommation totale
         et la production totale du dernier mois.
@@ -42,31 +44,31 @@ class AccOperation(models.Model):
                 la sommme de la prod totale de tous les producteurs
                 la date de début de mois
         """
+        self.ensure_one()
         # Get last date slot recorded
         last_record = self.get_last_cdc_record()
-        date_start, date_end = self.get_last_day("month", last_record)
+        date_start, date_end = self.get_interval("month", last_record)
         query = """
             SELECT
-                date_trunc('month', A.date_slot) AS date_slot,
+                date_trunc('month', cdc.date_slot) AS date_slot,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'cons' THEN A.power
+                    WHEN cdc.comp_data_type = 'cons' THEN cdc.power
                     ELSE 0 END) )/2) / 1000 as conso_tot,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'prod'
-                    THEN A.power ELSE 0 END) )/2) / 1000 as prod_tot,
+                    WHEN cdc.comp_data_type = 'prod'
+                    THEN cdc.power ELSE 0 END) )/2) / 1000 as prod_tot,
                 (SUM( (CASE WHEN
-                    comp_data_type = 'autocons' THEN A.power
+                    cdc.comp_data_type = 'autocons' THEN cdc.power
                     ELSE 0 END) )/2) / 1000 as autoconso_tot
             FROM
-                acc_enedis_cdc A
-            JOIN
-                acc_operation E ON E.id = A.acc_operation_id
+                acc_enedis_cdc cdc
+            INNER JOIN acc_operation ope
+                ON ope.id = cdc.acc_operation_id
             WHERE
-                A.acc_operation_id IS NOT NULL
-                AND A.acc_operation_id = %s
-                AND A.date_slot >= %s
-                AND A.date_slot <= %s
-            GROUP BY date_trunc('month', A.date_slot);
+                cdc.acc_operation_id = %s
+                AND cdc.date_slot >= %s
+                AND cdc.date_slot <= %s
+            GROUP BY date_trunc('month', cdc.date_slot);
         """
         query_params = (
             self.id,
@@ -74,8 +76,8 @@ class AccOperation(models.Model):
             date_end,
         )
         self.env.cr.execute(query, query_params)
-        raw_data = self.env.cr.fetchall()
-        return raw_data[0][1], raw_data[0][2], raw_data[0][3], date_start
+        raw_data = self.env.cr.fetchone()
+        return raw_data[1], raw_data[2], raw_data[3], date_start
 
     def get_last_cdc_record(self):
         """
@@ -99,91 +101,88 @@ class AccOperation(models.Model):
 
         return last_record
 
-    def get_last_day(self, scale, last_record):
+    def get_interval(self, scale, last_record):
         """
         Fonction retournant une date de début et une date de fin.
         Ces dates sont calculées en fonction de l'échelle choisie et du dernier
          élément enregistré
-        - day:  la date de début est égale à la dernière date
-                avec un enregistrement pour l'opération donnée
-                la date de fin ets la date de début + 1
-        - week: la date de début est égale à la dernière date
-                avec un enreisgtrement pour l'opération donnée moins 7 jours
-                la date de fin est égale à la dernière date
-                avec un enregistrement pour l'opération donnée
-        - month: la date de début est égale à la dernière date
-                avec un enreisgtrement pour l'opération donnée moins 1 mois
-                la date de fin est égale à la dernière date
-                avec un enregistrement pour l'opération donnée
-        - semestre: la date de début est égale à la dernière date
-                avec un enregistrement pour l'opération donnée moins 6 mois
-                la date de fin est égale à la dernière date
-                avec un enreisgtrement pour l'opération donnée
-        - year: la date de début est égale à la dernière date
-                avec un enregistrement pour l'opération donnée moins 1 an
-                la date de fin est égale à la dernière date
-                avec un enreisgtrement pour l'opération donnée
+        - day:  la date de début et la date de fin = dernier jour de données
+        - week: date de fin = fin du jour du dernier jour de données
+                date de début = date de fin moins 7 jours
+        - month: date de fin = fin du mois du dernier jour de données
+                date de début = début du mois du dernier jour de données
+        - year: date de fin = fin du mois du dernier jour de données
+                date de début = début de l'année du dernier jour de données
         :param str scale: type d'affichage des graphes
-                       (day/week/month/semestre/year)
+                       (day/week/month/year)
         :param object last_record: Dernier enregistrement dans la base
         @returns: une date de début et une date de fin
         """
 
         # Convert end datetime to timezone
-        last_day_start = date_utils.start_of(last_record.date_slot, "day")
-        last_day_end = date_utils.end_of(last_record.date_slot, "day")
-        end_month = date_utils.end_of(last_record.date_slot, "month")
+        last_day_start = datetime.combine(last_record.date_slot, time.min)
+        last_day_end = datetime.combine(last_record.date_slot, time.max)
+        start_month, end_month = date_utils.get_month(last_record.date_slot)
 
-        if scale == "semestre":
+        if scale == "year":
             date_end = end_month
-            date_start = end_month - relativedelta(months=6)
-        elif scale == "year":
+            date_start = start_month.replace(month=1)
+        elif scale == "month":
             date_end = end_month
-            date_start = end_month.replace(month=1, day=1)
+            date_start = start_month
         elif scale == "week":
-            date_start = last_day_end - relativedelta(days=7)
             date_end = last_day_end
+            date_start = last_day_end - relativedelta(days=7)
         elif scale == "day":
-            date_start = last_day_start
             date_end = last_day_end
-        # month by default
+            date_start = last_day_start
         else:
-            date_start = date_utils.start_of(end_month, "month")
-            date_end = end_month
+            raise ValueError(
+                _(
+                    "La période d'affichage est incorrecte : %s, "
+                    "valeurs attendues : day/week/month/year"
+                )
+                % scale
+            )
 
         return date_start, date_end
 
-    def get_step_from_date(self, date_start, date_end, scale=None):
+    def get_step_from_date(self, date_start, date_end):
         """
         Fonction retournant le pas des courbes en fonction de 2 dates.
-        :return: step: hour/day/month/year
+        :return:
+            display_hourly_curves (boolean) : whether or not hourly curves
+                should be displayed
+            step: hour/month/year
+            step_display_curve: hour/day/month/year
         """
+        display_hourly_curves = False
+        step = "hour"
+        step_display_curve = "hour"
         # Calculate delta between 2 dates
         delta = (date_end - date_start).days
-        if delta <= 1:
-            step_display_courbe = "hour"
-            step = "hour"
-        elif delta < 32:
-            step_display_courbe = "day"
-            step = "hour"
-            scale = "week"
-        elif delta > 365:
+        if delta < 32:
+            step_display_curve = "day"
+            display_hourly_curves = True
+        elif delta > 366:
             step = "year"
-            step_display_courbe = "year"
+            step_display_curve = "year"
         else:
             step = "month"
-            step_display_courbe = "month"
+            step_display_curve = "month"
 
-        return scale, step, step_display_courbe
+        return display_hourly_curves, step, step_display_curve
 
     def get_cdc_by_query_cons(self, slot_type, date_start, date_end, prm_ids=None):
         """
         Fonction permettant de récupérer les données pour la
         construction des chart pour une ou des opérations données
         pour les consommateurs
-        :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
+        :param  slot_type: type de slot pour la query ("hour", "month" ou
+                    "year")
                 date_start: date début
                 date_end: date de fin
+                prm_ids : liste des PRMs de soutirage à récupérer
         @returns: un dictionnaire de données
                 (labels et data pour les charts à afficher)
         """
@@ -193,33 +192,29 @@ class AccOperation(models.Model):
         data_allocons = []
         data_cons = []
         data_prod = []
-        data_surplus = []
 
         query = """
             SELECT
-                date_trunc(%s, A.date_slot) AS date_slot,
-                (SUM( (CASE WHEN
-                    comp_data_type = 'autocons' THEN A.power
-                    ELSE 0 END) )/2) / 1000 as autocons,
+                date_trunc(%s, cdc.date_slot) AS date_slot,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'prod'
-                    THEN A.power ELSE 0 END) )/2) / 1000 as prod,
-                ((SUM( (CASE WHEN comp_data_type = 'cons' THEN A.power ELSE 0 END)) -
-                    SUM(CASE WHEN comp_data_type = 'autocons' THEN A.power ELSE 0 END) ) / 2) / 1000 as allocons,
+                    WHEN cdc.comp_data_type = 'cons'
+                    THEN cdc.power ELSE 0 END) )/2) / 1000 as cons,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'cons' THEN A.power
-                    ELSE 0 END) )/2) / 1000 as cons
+                    WHEN cdc.comp_data_type = 'autocons'
+                    THEN cdc.power ELSE 0 END) )/2) / 1000 as autocons,
+                (SUM( (CASE
+                    WHEN cdc.comp_data_type = 'prod'
+                    THEN cdc.power ELSE 0 END) )/2) / 1000 as prod
             FROM
-                acc_enedis_cdc A
-            JOIN
-                acc_operation E ON E.id = A.acc_operation_id
+                acc_enedis_cdc cdc
+            INNER JOIN acc_operation ope
+                 ON ope.id = cdc.acc_operation_id
             WHERE
-                A.acc_operation_id IS NOT NULL
-                AND A.acc_operation_id IN %s
-                AND ( A.acc_counter_id IN %s OR A.comp_data_type = 'prod' )
-                AND A.date_slot >= %s
-                AND A.date_slot <= %s
-            GROUP BY date_trunc(%s, A.date_slot)
+                cdc.acc_operation_id IN %s
+                AND ( cdc.acc_counter_id IN %s OR cdc.comp_data_type = 'prod' )
+                AND cdc.date_slot >= %s
+                AND cdc.date_slot <= %s
+            GROUP BY date_trunc(%s, cdc.date_slot)
             ORDER BY date_slot ASC;
             """
         query_params = (
@@ -233,31 +228,28 @@ class AccOperation(models.Model):
         self.env.cr.execute(query, query_params)
         raw_data = self.env.cr.fetchall()
         for row in raw_data:
-            data_autocons.append({"x": row[0], "y": round(row[1], 2)})
-            data_prod.append({"x": row[0], "y": round(row[2], 2)})
-            data_allocons.append({"x": row[0], "y": round(row[3], 2)})
-            data_cons.append({"x": row[0], "y": round(row[4], 2)})
             label.append(row[0])
+            data_cons.append({"x": row[0], "y": round(row[1], 2)})
+            data_autocons.append({"x": row[0], "y": round(row[2], 2)})
+            data_allocons.append({"x": row[0], "y": round(row[1] - row[2], 2)})
+            data_prod.append({"x": row[0], "y": round(row[3], 2)})
 
-        cdc_jour = {
+        cdc_cons = {
+            "label": label,
             "autocons": data_autocons,
-            "prod": data_prod,
             "allocons": data_allocons,
-            "label": label,
             "cons": data_cons,
-            "surplus": data_surplus,
+            "prod": data_prod,
         }
-        return cdc_jour
+        return cdc_cons
 
-    def get_cdc_by_query_histo_cons(
-        self, slot_type, date_start, date_end, prm_ids=None
-    ):
+    def get_cdc_by_query_daily_histo_cons(self, date_start, date_end, prm_ids=None):
         """
         Fonction permettant de récupérer les données pour la construction
         des chart pour une ou des opérations données pour les consommateurs
-        :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
-                date_start: date début
+        :param  date_start: date début
                 date_end: date de fin
+                prm_ids: liste des PRMs de soutirage à récupérer
         :return: un dictionnaire de données
                 (labels et data pour les charts à afficher)
         """
@@ -267,29 +259,31 @@ class AccOperation(models.Model):
 
         query = """
             SELECT
-                date_trunc(%s, A.date_slot) AS date_slot,
+                date_trunc('day', cdc.date_slot) AS date_slot,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'autocons'
-                    THEN A.power ELSE 0 END) )/2) / 1000 as autocons,
-                ((SUM( (CASE WHEN comp_data_type = 'cons' THEN A.power ELSE 0 END)) -
-                    SUM(CASE WHEN comp_data_type = 'autocons' THEN A.power ELSE 0 END) ) / 2) / 1000 as allocons
-                FROM acc_enedis_cdc A
-                    JOIN acc_operation E ON E.id = A.acc_operation_id
-                WHERE A.acc_operation_id IS NOT NULL
-                    AND A.acc_operation_id IN %s
-                    AND A.acc_counter_id IN %s
-                    AND A.date_slot >= %s
-                    AND A.date_slot <= %s
-                GROUP BY date_trunc(%s, A.date_slot)
+                    WHEN cdc.comp_data_type = 'autocons'
+                    THEN cdc.power ELSE 0 END) )/2) / 1000 as autocons,
+                ((SUM( (CASE
+                    WHEN cdc.comp_data_type = 'cons'
+                    THEN cdc.power ELSE 0 END)) -
+                    SUM(CASE
+                        WHEN cdc.comp_data_type = 'autocons'
+                        THEN cdc.power ELSE 0 END) ) / 2) / 1000 as allocons
+                FROM acc_enedis_cdc cdc
+                INNER JOIN acc_operation ope
+                    ON ope.id = cdc.acc_operation_id
+                WHERE cdc.acc_operation_id IN %s
+                    AND cdc.acc_counter_id IN %s
+                    AND cdc.date_slot >= %s
+                    AND cdc.date_slot <= %s
+                GROUP BY date_trunc('day', cdc.date_slot)
                 ORDER BY date_slot ASC;
             """
         query_params = (
-            slot_type,
             tuple(self.ids),
             tuple(prm_ids.ids),
             date_start,
             date_end,
-            slot_type,
         )
         self.env.cr.execute(query, query_params)
         raw_data = self.env.cr.fetchall()
@@ -298,50 +292,50 @@ class AccOperation(models.Model):
             data_allocons_histo.append(round(row[2], 2))
             label_histo.append(row[0])
 
-        cdc_jour = {
+        cdc_cons = {
             "autocons_histo": data_autocons_histo,
             "allocons_histo": data_allocons_histo,
             "label_histo": label_histo,
         }
-        return cdc_jour
+        return cdc_cons
 
     def get_cdc_by_query_prod(self, slot_type, date_start, date_end, prm_ids=None):
         """
-        Fonction permettant de récupérer les données pour la construction des chart
-         pour une ou des opérations données pour les consommateurs
-        :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
+        Fonction permettant de récupérer les données pour la construction des
+          chart pour une ou des opérations données pour les consommateurs
+        :param  slot_type: type de slot pour la query ("hour", "month"
+                    ou "year")
                 date_start: date début
                 date_end: date de fin
+                prm_ids: liste des PRMs d'injection à récupérer
         :return: un dictionnaire de données
                 (labels et data pour les charts à afficher)
         """
         label = []
         data_autocons = []
         data_surplus = []
-        label_histo = []
-        data_autocons_histo = []
-        data_surplus_histo = []
 
         query = """
             SELECT
-                date_trunc(%s, A.date_slot) AS date_slot,
+                date_trunc(%s, cdc.date_slot) AS date_slot,
                 ((SUM((CASE
-                    WHEN comp_data_type = 'prod' THEN A.power
+                    WHEN cdc.comp_data_type = 'prod' THEN cdc.power
                     ELSE 0 END))
                  - SUM(CASE
-                    WHEN comp_data_type = 'surplus' THEN A.power
+                    WHEN cdc.comp_data_type = 'surplus' THEN cdc.power
                     ELSE 0 END)) / 2) / 1000 as autocons,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'surplus' THEN A.power
+                    WHEN cdc.comp_data_type = 'surplus' THEN cdc.power
                     ELSE 0 END) )/2) / 1000 as surplus
-            FROM acc_enedis_cdc A
-                JOIN acc_operation E ON E.id = A.acc_operation_id
-            WHERE A.acc_operation_id IS NOT NULL
-                AND A.acc_counter_id IN %s
-                AND A.acc_operation_id IN %s
-                AND A.date_slot >= %s
-                AND A.date_slot <= %s
-            GROUP BY date_trunc(%s, A.date_slot)
+            FROM acc_enedis_cdc cdc
+            INNER JOIN acc_operation ope
+                ON ope.id = cdc.acc_operation_id
+            WHERE
+                cdc.acc_counter_id IN %s
+                AND cdc.acc_operation_id IN %s
+                AND cdc.date_slot >= %s
+                AND cdc.date_slot <= %s
+            GROUP BY date_trunc(%s, cdc.date_slot)
             ORDER BY date_slot ASC;
             """
         query_params = (
@@ -355,33 +349,24 @@ class AccOperation(models.Model):
         self.env.cr.execute(query, query_params)
         raw_data = self.env.cr.fetchall()
         for row in raw_data:
-            if slot_type == "day":
-                data_autocons_histo.append(round(row[1], 2))
-                data_surplus_histo.append(round(row[2], 2))
-                label_histo.append(row[0])
+            label.append(row[0])
             data_autocons.append({"x": row[0], "y": round(row[1], 2)})
             data_surplus.append({"x": row[0], "y": round(row[2], 2)})
-            label.append(row[0])
 
-        cdc_jour = {
-            "autocons_prod": data_autocons,
+        cdc_prod = {
             "label": label,
+            "autocons_prod": data_autocons,
             "surplus": data_surplus,
-            "autocons_prod_histo": data_autocons_histo,
-            "label_histo": label_histo,
-            "surplus_histo": data_surplus_histo,
         }
-        return cdc_jour
+        return cdc_prod
 
-    def get_cdc_by_query_histo_prod(
-        self, slot_type, date_start, date_end, prm_ids=None
-    ):
+    def get_cdc_by_query_daily_histo_prod(self, date_start, date_end, prm_ids=None):
         """
-        Fonction permettant de récupérer les données pour la construction des chart
-        pour une ou des opérations données pour les consommateurs
-        :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
-                date_start: date début
+        Fonction permettant de récupérer les données pour la construction des
+        chart pour une ou des opérations données pour les consommateurs
+        :param  date_start: date début
                 date_end: date de fin
+                prm_ids: liste des PRMs d'injection à récupérer
         :return: un dictionnaire de données
                 (labels et data pour les charts à afficher)
         """
@@ -391,48 +376,54 @@ class AccOperation(models.Model):
 
         query = """
             SELECT
-                date_trunc(%s, A.date_slot) AS date_slot,
+                date_trunc('day', cdc.date_slot) AS date_slot,
                 ((SUM((CASE
-                    WHEN comp_data_type = 'prod' THEN A.power
+                    WHEN cdc.comp_data_type = 'prod' THEN cdc.power
                     ELSE 0 END))
                  - SUM(CASE
-                    WHEN comp_data_type = 'surplus' THEN A.power
+                    WHEN cdc.comp_data_type = 'surplus' THEN cdc.power
                     ELSE 0 END)) / 2) / 1000 as autocons,
                 (SUM( (CASE
-                    WHEN comp_data_type = 'surplus' THEN A.power
+                    WHEN cdc.comp_data_type = 'surplus' THEN cdc.power
                     ELSE 0 END) )/2) / 1000 as surplus
-            FROM acc_enedis_cdc A
-                JOIN acc_operation E ON E.id = A.acc_operation_id
-            WHERE A.acc_operation_id IS NOT NULL
-                AND A.acc_counter_id IN %s
-                AND A.acc_operation_id IN %s
-                AND A.date_slot >= %s
-                AND A.date_slot <= %s
-            GROUP BY date_trunc(%s, A.date_slot)
+            FROM acc_enedis_cdc cdc
+            INNER JOIN acc_operation ope
+                ON ope.id = cdc.acc_operation_id
+            WHERE
+                cdc.acc_counter_id IN %s
+                AND cdc.acc_operation_id IN %s
+                AND cdc.date_slot >= %s
+                AND cdc.date_slot <= %s
+            GROUP BY date_trunc('day', cdc.date_slot)
             ORDER BY date_slot ASC;
                 """
         query_params = (
-            slot_type,
             tuple(prm_ids.ids),
             tuple(self.ids),
             date_start,
             date_end,
-            slot_type,
         )
         self.env.cr.execute(query, query_params)
         raw_data = self.env.cr.fetchall()
         for row in raw_data:
+            label_histo.append(row[0])
             data_autocons_prod_histo.append(round(row[1], 2))
             data_surplus_histo.append(round(row[2], 2))
-            label_histo.append(row[0])
 
         cdc_jour = {
-            "autocons_prod_histo": data_autocons_prod_histo,
             "label_histo": label_histo,
+            "autocons_prod_histo": data_autocons_prod_histo,
             "surplus_histo": data_surplus_histo,
         }
         return cdc_jour
 
+    def get_date_min_max(self):
+        self.ensure_one()
+        last_record = self.get_last_cdc_record()
+        date_max = last_record.date_slot.strftime("%d/%m/%Y")
+        date_min = self.date_start_contract.strftime("%d/%m/%Y")
+        return {"date_min": date_min, "date_max": date_max}
+
     # ------------------------------------------------------
     # Functions to manage route
     # ------------------------------------------------------
@@ -445,80 +436,73 @@ class AccOperation(models.Model):
         data_type=None,
     ):
         """
-        Fonction appelée pour l'affichage des courbes consommation
+        Fonction appelée pour l'affichage des courbes globales
         sur le portail
-        :param scale: type d'affichage des graphes
-                       (day/week/month/semestre/year)
-                        défini par le clic bouton
+        :param  date_start: date début
+                date_end: date de fin
+                partner_id: données uniquement de ce contact
+                prm_id: données uniquement de ce PRM (mutuellement exclusif de
+                    partner_id)
+                data_type: type de courbes à afficher:
+                  - "pmo" : vue globale (cons + prod sans filtrage)
+                  - "cons" : vue mon suivi conso (avec filtrage possible)
+                  - "prod" : vue mon suivi production (avec filtrage possible)
         @returns: dictionnaire pour la construction des graphes
         """
+        self.ensure_one()
         result_graph = {}
         date_start = datetime.strptime(date_start, "%d/%m/%Y")
-        date_end = datetime.strptime(date_end, "%d/%m/%Y")
-        date_end = date_utils.end_of(date_end, "day")
-        scale, step_courbe, step_display_courbe = self.get_step_from_date(
-            date_start=date_start, date_end=date_end, scale=False
+        date_end = datetime.combine(datetime.strptime(date_end, "%d/%m/%Y"), time.max)
+        display_hourly_curves, step_curve, step_display_curve = self.get_step_from_date(
+            date_start=date_start, date_end=date_end
         )
 
-        if data_type == "pmo":
-            acc_counter_ids = (
-                self.env["acc.counter"]
-                .sudo()
-                .search([("acc_operation_id", "=", self.id)])
-            )
-        else:
-            # Get PRM ids
-            if prm_id:
-                acc_counter_ids = self.env["acc.counter"].browse(prm_id)
-            elif partner_id:
-                acc_counter_ids = self.env["acc.counter"].search(
-                    [("partner_id", "=", partner_id)]
-                )
-            else:
-                acc_counter_ids = self.acc_delivery_ids + self.acc_injection_ids
+        # TODO: ajouter filtre par période de PRM en fonction date de début / fin
+        # (si prm_id ou partner_id)
 
-        if scale == "week" or scale == "day":
-            is_curve_line = True
+        # Si prm_id alors filtrer pour n'afficher que ce compteur
+        if prm_id:
+            acc_counter_ids = self.env["acc.counter"].browse(prm_id)
         else:
-            is_curve_line = False
+            # Filtre par défaut = même opération
+            domain = [["acc_operation_id", "=", self.id]]
+            # Si partner_id alors on ne prend que les PRMs appartenant à ce contact
+            if partner_id:
+                domain = expression.AND([domain, [("partner_id", "=", partner_id)]])
+            acc_counter_ids = (
+                self.env["acc.counter.period"].search(domain).mapped("acc_counter_id")
+            )
 
         chart_data = {}
         if data_type == "cons" or data_type == "pmo":
             chart_data_cons = self.get_cdc_by_query_cons(
-                step_courbe, date_start, date_end, acc_counter_ids
+                step_curve, date_start, date_end, acc_counter_ids
             )
-            if scale == "week":
-                chart_data_histo = self.get_cdc_by_query_histo_cons(
-                    "day", date_start, date_end, acc_counter_ids
+            if display_hourly_curves:
+                chart_data_histo = self.get_cdc_by_query_daily_histo_cons(
+                    date_start, date_end, acc_counter_ids
                 )
                 chart_data_cons.update(chart_data_histo)
             chart_data.update(chart_data_cons)
         if data_type == "prod" or data_type == "pmo":
             chart_data_prod = self.get_cdc_by_query_prod(
-                step_courbe, date_start, date_end, acc_counter_ids
+                step_curve, date_start, date_end, acc_counter_ids
             )
-            if scale == "week":
-                chart_data_histo = self.get_cdc_by_query_histo_prod(
-                    "day", date_start, date_end, acc_counter_ids
+            if display_hourly_curves:
+                chart_data_histo = self.get_cdc_by_query_daily_histo_prod(
+                    date_start, date_end, acc_counter_ids
                 )
                 chart_data_prod.update(chart_data_histo)
             chart_data.update(chart_data_prod)
 
         result_graph["chart_data"] = chart_data
-        last_record = self.get_last_cdc_record()
-        date_deb, date_max = self.get_last_day("day", last_record)
-        date_max = date_max.strftime("%d/%m/%Y")
-        date_min = self.date_start_contract
-
-        date_min = date_min.strftime("%d/%m/%Y")
+        result_graph.update(self.get_date_min_max())
         result_graph.update(
             {
                 "date_start": date_start,
                 "date_end": date_end,
-                "date_min": date_min,
-                "date_max": date_max,
-                "scale": step_display_courbe,
-                "is_curve_line": is_curve_line,
+                "scale": step_display_curve,
+                "is_curve_line": display_hourly_curves,
             }
         )
         return result_graph
diff --git a/views/acc_operation_views.xml b/views/acc_operation_views.xml
index d9773946b463d836e1f8ae4c94ccbf6c8745c009..60db26eeb7a10d7ed371699d66242b3417b3aa8a 100644
--- a/views/acc_operation_views.xml
+++ b/views/acc_operation_views.xml
@@ -11,7 +11,7 @@
                     string="Voir les courbes"
                     type="object"
                     class="btn-primary"
-                    name="action_view_courbes"
+                    name="action_view_curves"
                 />
             </header>
         </field>