Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • f448440a91bf009e5725614f3b8290217f166ba7
  • 14.0 par défaut protégée
  • 16.0
  • 14.0_optim
4 résultats

enercoop_operation.py

Blame
  • acc_operation.py 51,14 Kio
    # Copyright 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
    from datetime import datetime, timedelta
    from odoo.tools import date_utils
    
    import dateutil.parser as parser
    from dateutil.relativedelta import relativedelta
    
    
    class AccOperation(models.Model):
        _inherit = 'acc.operation'
    
        # ------------------------------------------------------
        # Actions
        # ------------------------------------------------------
        def action_view_courbes(self):
            """
            Action qui ouvre la vue Qweb
            :return: Vue Qweb
            """
            self.ensure_one()
            partner_id = self.env['res.partner'].browse(self.env.context.get('default_partner_id'))
            action = self.env["ir.actions.actions"]._for_xml_id(
                "acc_cdc.acc_operation_action_client_courbes")
            action['params'] = {
                'operation_ids': self.ids,
            }
            action['context'] = {
                'active_id': self.id,
                'active_ids': self.ids,
                'search_default_name': self.name,
            }
            return action
    
        # ------------------------------------------------------
        # Business methods
        # ------------------------------------------------------
        def get_auto_power_tot(self):
            """
            Fonction retournant l autoconsommation totale du dernier mois.
            :return: la somme de l'autoconso totale de tous les consommateurs
            """
            # Récupère les dates du dernier mois disponible
            date_start, date_end = self.get_last_day('month')
            # Conso Totale
            autoconso_ids = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', '=', self.id),
                ('comp_data_type', '=', 'autocons'),
                ('date_slot', '>=', date_start),
                ('date_slot', '<', date_end)])
            autoconso_tot = (sum(autoconso_ids.mapped('power')) / 1000) / 2
    
            return autoconso_tot
    
        def get_power_tot(self):
            """
            Fonction retournant la consommation totale, l'autoconsommation totale et la production totale du dernier mois.
            :return: la somme de la conso totale de tous les consommateurs,
                    la somme de l autoconso totale de tous les consommateurs,
                    la sommme de la prod totale de tous les producteurs
            """
            # Récupère les dates du dernier mois disponible
            date_start, date_end = self.get_last_day('month')
            # Conso Totale
            conso_ids = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', '=', self.id),
                ('comp_data_type', '=', 'cons'),
                ('date_slot', '>=', date_start),
                ('date_slot', '<', date_end)])
            conso_tot = (sum(conso_ids.mapped('power')) / 1000) / 2
    
            # Prod Totale
            prod_ids = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', '=', self.id),
                ('comp_data_type', '=', 'prod'),
                ('date_slot', '>=', date_start),
                ('date_slot', '<', date_end)])
            prod_tot = (sum(prod_ids.mapped('power')) / 1000) / 2
    
            # Auto cons Totale
            autoconso_ids = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', '=', self.id),
                ('comp_data_type', '=', 'autocons'),
                ('date_slot', '>=', date_start),
                ('date_slot', '<', date_end)])
            autoconso_tot = (sum(autoconso_ids.mapped('power')) / 1000) / 2
            return conso_tot, prod_tot, autoconso_tot
    
        def get_power_install_tot(self):
            """
            Fonction retournant la puissance totale installée.
            :return: la somme de toutes les puissances d'injection
            """
            puiss_tot = 0.0
    
            for counter in self.acc_injection_ids:
                puiss_tot += counter.acc_counter_id.power_instal
    
            return puiss_tot
    
        def get_last_day(self, scale):
            """
            Fonction retournant une date de début et une date de fin.
            Ces dates sont calculées en fonction de l'échelle choisie
            - day:  la date de début est égale à la dernière date
                    avec un enreisgtrement 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 enreisgtrement 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 enreisgtrement pour l'opération donnée
            - semestre: la date de début est égale à la dernière date
                    avec un enreisgtrement 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 enreisgtrement 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
            :param  scale: type d'affichage des graphes
                           (day/week/month/semestre/year)
            :return: une date de début et une date de fin
            """
    
            # Get last date slot recorded
            last_record = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', 'in', self.ids),
            ], limit=1, order='date_slot DESC')
            date_end = last_record.date_slot
    
            if scale == 'semestre':
                date_first = date_end - relativedelta(months=1)
                date_end = date_utils.end_of(date_first, 'month')
                date_start = date_end - relativedelta(months=5)
                date_start = date_utils.start_of(date_start, 'month')
            elif scale == 'month':
                date_start = date_end - relativedelta(months=1)
                date_start = date_utils.start_of(date_start, scale)
                date_end = date_utils.end_of(date_start, scale)
            elif scale == 'week':
                date_start = date_end - relativedelta(days=6)
                date_start = date_utils.start_of(date_start, 'day')
            elif scale == 'day':
                date_start = date_utils.start_of(date_end, 'day')
            else:
                date_first = date_end - relativedelta(months=1)
                date_end = date_utils.end_of(date_first, 'month')
                date_start = date_utils.start_of(date_end, scale)
    
            return date_start, date_end
    
        def get_first_day(self):
            """
            Fonction retournant la première date où des données ont été enregistrées.
            :return: une date
            """
    
            # Get last date slot recorded
            first_record = self.env['acc.enedis.cdc'].search([
                ('acc_operation_id', 'in', self.ids),
            ], limit=1, order='date_slot ASC')
    
            date_min = first_record.date_slot
            return date_min
    
        def get_step_from_date(self, date_start, date_end, scale=None):
            """
            Fonction retournant le pas des courbes en fonction de 2 dates.
            :return: step: hour/day/month/year
            """
            # Calculate delta between 2 dates
            delta = (date_end - date_start).days
            if delta < 1:
                step_display_courbe = 'hour'
                step = 'hour'
                if not scale:
                    scale = 'day'
            elif delta < 29:
                step_display_courbe = 'day'
                step = 'hour'
                if not scale:
                    scale = 'week'
            elif delta <= 365:
                step = 'month'
                step_display_courbe = 'month'
                if not scale:
                    scale = 'month'
            else:
                step = 'month'
                step_display_courbe = 'month'
                if not scale:
                    scale = 'year'
    
            return scale, step, step_display_courbe
    
        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')
                    date_start: date début
                    date_end: date de fin
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            label = []
            data_autocons = []
            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,
                    (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
                    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 OR A.comp_data_type = 'prod' )
                        AND A.date_slot >= %s
                        AND A.date_slot < %s
                    GROUP BY date_trunc(%s, A.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()
            for row in raw_data:
                if slot_type == 'month' or slot_type == 'year':
                    data_autocons.append(int(row[1]))
                    data_prod.append(int(row[2]))
                    data_allocons.append(int(row[3]))
                    label.append(row[0])
                else:
                    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)})
                    label.append(row[0])
    
            cdc_jour = {
                'autocons': data_autocons,
                'prod': data_prod,
                'allocons': data_allocons,
                'label': label,
                'cons': data_cons,
                'surplus': data_surplus,
            }
            return cdc_jour
    
        def get_cdc_by_query_histo_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')
                    date_start: date début
                    date_end: date de fin
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            label_histo = []
            data_autocons_histo = []
            data_allocons_histo = []
    
            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,
                    ((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)
                        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()
            for row in raw_data:
                data_autocons_histo.append(round(row[1], 2))
                data_allocons_histo.append(round(row[2], 2))
                label_histo.append(row[0])
    
            cdc_jour = {
                'autocons_histo': data_autocons_histo,
                'allocons_histo': data_allocons_histo,
                'label_histo': label_histo,
            }
            return cdc_jour
    
        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')
                    date_start: date début
                    date_end: date de fin
            :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,
                    ((SUM((CASE WHEN comp_data_type = 'prod' THEN A.power ELSE 0 END)) - SUM(CASE
                        WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END)) / 2) / 1000 as autocons,
                    (SUM( (CASE WHEN comp_data_type = 'surplus' THEN A.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)
                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:
                if slot_type == 'month' or slot_type == 'year':
                    data_autocons.append(int(row[1]))
                    data_surplus.append(int(row[2]))
                    label.append(row[0])
                elif slot_type == 'day':
                    data_autocons_histo.append(round(row[1], 2))
                    data_surplus_histo.append(round(row[2], 2))
                    label_histo.append(row[0])
                else:
                    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,
                'label': label,
                'surplus': data_surplus,
                'autocons_histo': data_autocons_histo,
                'label_histo': label_histo,
                'surplus_histo': data_surplus_histo,
            }
            return cdc_jour
    
        def get_cdc_by_query_histo_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')
                    date_start: date début
                    date_end: date de fin
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            label_histo = []
            data_autocons_prod_histo = []
            data_surplus_histo = []
    
            query = """
                SELECT
                    date_trunc(%s, A.date_slot) AS date_slot,
                    ((SUM((CASE WHEN comp_data_type = 'prod' THEN A.power ELSE 0 END)) - SUM(CASE
                        WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END)) / 2) / 1000 as autocons,
                    (SUM( (CASE WHEN comp_data_type = 'surplus' THEN A.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)
                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:
                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,
                'surplus_histo': data_surplus_histo,
            }
            return cdc_jour
    
        def get_cdc_by_query(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
            :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
                    date_start: date début
                    date_end: date de fin
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            label = []
            data_autocons = []
            data_autocons_prod = []
            data_allocons = []
            data_cons = []
            data_prod = []
            data_surplus = []
    
            # if prm_ids:
            query = """
                SELECT
                    date_trunc(%s, A.date_slot) AS date_slot,
                    (SUM((CASE WHEN comp_data_type = 'cons' THEN A.power ELSE 0 END)) / 2) / 1000 as cons,
                    (SUM((CASE WHEN comp_data_type = 'autocons' THEN A.power ELSE 0 END)) / 2) / 1000 as autocons,
                    (SUM((CASE WHEN comp_data_type = 'prod' THEN A.power ELSE 0 END)) / 2) / 1000 as prod_s,
                    (SUM( (CASE WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END) )/2) / 1000 as surplus,
                    ((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,
                    ((SUM((CASE WHEN comp_data_type = 'prod' THEN A.power ELSE 0 END)) - SUM(CASE
                        WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END)) / 2) / 1000 as autocons_prod
                        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.date_slot >= %s
                            AND A.date_slot < %s
                        GROUP BY date_trunc(%s, A.date_slot)
                        ORDER BY date_slot ASC;
                    """
            query_params = (slot_type, 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:
                if slot_type == 'month' or slot_type == 'year':
                    data_cons.append(int(row[1]))
                    data_autocons.append(int(row[2]))
                    data_prod.append(int(row[3]))
                    data_surplus.append(int(row[4]))
                    data_allocons.append(int(row[5]))
                    data_autocons_prod.append(int(row[6]))
                    label.append(row[0])
                else:
                    data_cons.append({'x': row[0], 'y': round(row[1], 2)})
                    data_autocons.append({'x': row[0], 'y': round(row[2], 2)})
                    data_prod.append({'x': row[0], 'y': round(row[3], 2)})
                    data_surplus.append({'x': row[0], 'y': round(row[4], 2)})
                    data_allocons.append({'x': row[0], 'y': round(row[5], 2)})
                    data_autocons_prod.append({'x': row[0], 'y': round(row[6], 2)})
                    label.append(row[0])
    
            cdc_jour = {
                'autocons': data_autocons,
                'autocons_prod': data_autocons_prod,
                'cons': data_cons,
                'prod': data_prod,
                'surplus': data_surplus,
                'allocons': data_allocons,
                'label': label,
            }
            return cdc_jour
    
        def get_cdc_by_query_histo(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
            :param  slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
                    date_start: date début
                    date_end: date de fin
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            label_histo = []
            data_autocons_histo = []
            data_autocons_prod_histo = []
            data_allocons_histo = []
            data_surplus_histo = []
    
            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,
                    (SUM( (CASE WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END) )/2) / 1000 as surplus,
                    ((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,
                    ((SUM((CASE WHEN comp_data_type = 'prod' THEN A.power ELSE 0 END)) - SUM(CASE
                        WHEN comp_data_type = 'surplus' THEN A.power ELSE 0 END)) / 2) / 1000 as autocons_prod
                        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.date_slot >= %s
                            AND A.date_slot < %s
                        GROUP BY date_trunc(%s, A.date_slot)
                        ORDER BY date_slot ASC;
                    """
            query_params = (slot_type, 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:
                data_autocons_histo.append(round(row[1], 2))
                data_surplus_histo.append(round(row[2], 2))
                data_allocons_histo.append(round(row[3], 2))
                data_autocons_prod_histo.append(round(row[4], 2))
                label_histo.append(row[0])
    
            cdc_jour = {
                'autocons_histo': data_autocons_histo,
                'surplus_histo': data_surplus_histo,
                'allocons_histo': data_allocons_histo,
                'autocons_prod_histo': data_autocons_prod_histo,
                'label_histo': label_histo,
            }
            return cdc_jour
    
        def chart_data_line_cons(self, chart_data, scale):
            """
            Fonction retournant le dictionnaire permettant la construiction
            des graphes de la partie consommation par mois
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
            if scale == 'day':
                offsetGridLines = False
            else:
                offsetGridLines = True
            result = {}
    
            result['line_chart_conso_line'] = {
                'type': 'line',
                'data': {
                        'labels': chart_data['label'],
                        'datasets': [
                            {
                                'label': 'Allo Conso',
                                'data': chart_data['allocons'],
                                'backgroundColor': 'rgba(57, 120, 187, 0.2)',
                                'borderColor': 'rgba(57, 120, 187, 1)',
                                'borderWidth': 1,
                                'hoverRadius': 1,
                                'radius': 0,
                            },
                            {
                                'label': 'Production solaire',
                                'data': chart_data['prod'],
                                'backgroundColor': 'rgba(244, 165, 25, 0)',
                                'borderColor': 'rgba(244, 165, 25, 1)',
                                'borderWidth': 2,
                                'hoverRadius': 1,
                                'radius': 0,
                            },
                            {
                                'label': 'Autoconso',
                                'data': chart_data['autocons'],
                                'backgroundColor': 'rgba(91, 154, 81, 0.4)',
                                'borderColor': 'rgba(91, 154, 81, 1)',
                                'borderWidth': 2,
                                'hoverRadius': 1,
                                'radius': 0,
                            },
                        ],
                    },
                    'options': {
                        'scales': {
                            'xAxes': [{
                                'type': 'time',
                                'time': {
                                    'unit': scale,
                                },
                                'gridLines': {
                                    'offsetGridLines': offsetGridLines
                                },
                            }],
                            'yAxes': [{
                                'scaleLabel': {
                                    'display': True,
                                    'labelString': 'kW',
                                }
                            }]
                        },
                        'tooltips': {
                            'backgroundColor': '#f5f5f5',
                            'titleFontColor': '#333',
                            'bodyFontColor': '#666',
                            'bodySpacing': 4,
                            'xPadding': 12,
                            'mode': 'x',
                            'intersect': False,
                        },
                        'elements': {
                            'point': {
                                'radius': 0
                            }
                        }
                    },
                }
            result['line_chart_prod_prm'] = {
                'type': 'line',
                'data': {
                    'labels': chart_data['label'],
                    'datasets': [
                        {
                            'label': 'Production solaire',
                            'data': chart_data['prod'],
                            'backgroundColor': 'rgba(244, 165, 25, 0)',
                            'borderColor': 'rgba(244, 165, 25, 1)',
                        },
                    ],
                },
            }
            return result
    
        def chart_data_histo_cons(self, chart_data, scale, scale_spe):
            """
            Fonction retournant le dictionnaire permettant la construiction
            des graphes de la partie consommation par mois
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
    
            result = {}
            if scale_spe == 'week':
                data_autocons = chart_data['autocons_histo']
                data_allocons = chart_data['allocons_histo']
                data_label = chart_data['label_histo']
            else:
                data_autocons = chart_data['autocons']
                data_allocons = chart_data['allocons']
                data_label = chart_data['label']
            result['histo_chart_conso'] = {
                'type': 'bar',
                'data': {
                    'labels': data_label,
                    'datasets': [
                        {
                            'label': 'AutoConso',
                            'data': data_autocons,
                            'backgroundColor': 'rgba(91, 154, 81, 0.4)',
                            'hoverBackgroundColor': 'rgba(91, 154, 81, 0.7)',
                        },
                        {
                            'label': 'AlloConso',
                            'data': data_allocons,
                            'backgroundColor': 'rgba(57, 120, 187, 0.4)',
                            'hoverBackgroundColor': 'rgba(57, 120, 187, 0.7)',
                        }]
                    },
                'options': {
                    'plugins': {
                        'datalabels': {
                            'color': 'white',
                            'font': {
                            'weight': 'bold'
                            },
                        }
                    },
                    'interaction': {
                        'intersect': False,
                    },
                    'scales': {
                        'xAxes': [{
                            'type': 'time',
                            'time': {
                                'unit': scale
                            },
                            'stacked': True,
                            'offset': True,
                            'gridLines': {
                                'offsetGridLines': True
                            },
    
                        }],
                        'yAxes': [{
                            'stacked': True,
                            'ticks': {
                                'beginAtZero': True,
                            },
                            'scaleLabel': {
                                'display': True,
                                'labelString': 'kWh',
                            }
                        }]
                    },
                    'tooltips': {
                        'backgroundColor': '#f5f5f5',
                        'titleFontColor': '#333',
                        'bodyFontColor': '#666',
                        'bodySpacing': 4,
                        'xPadding': 12,
                        'mode': 'nearest',
                        'intersect': 0,
                    }
                }
            }
            return result
    
        def chart_data_donuts_cons(self, chart_data, scale):
            """
            Fonction retournant le dictionnaire permettant la construiction
            des graphes de la partie consommation par mois
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
    
            result = {}
    
            if scale == 'hour':
                sum_res1 = sum(int(item['y']) for item in chart_data['autocons'])
                sum_res2 = sum(int(item['y']) for item in chart_data['allocons'])
            else:
                sum_res1 = sum(chart_data['autocons'])
                sum_res2 = sum(chart_data['allocons'])
    
            if sum_res1 == 0:
                label = ['Alloconso']
                res = [sum_res2]
            elif sum_res2 == 0:
                label = ['Autoconso']
                res = [sum_res1]
            else:
                label = ['Autoconso', 'Alloconso']
                res = [sum_res1, sum_res2]
    
            result['donuts_chart_conso'] = {
                'type': 'doughnut',
                'data': {
                    'labels': label,
                    'datasets': [{
                        'label': 'Inférieur à 3',
                        'data': res,
                        'backgroundColor': [
                            'rgba(91, 154, 81, 0.4)',
                            'rgba(57, 120, 187, 0.4)',
                        ],
                        'hoverBackgroundColor': [
                            'rgba(91, 154, 81, 0.7)',
                            'rgba(57, 120, 187, 0.7)',
                        ],
                        'borderWidth': 1
                    }],
                },
                'options': {
                    'cutoutPercentage': 60,
                    'animation': {
                        'animateScale': True,
                    },
                    'plugins': {
                        'datalabels': {
                            'color': 'white',
                            'font': {
                              'weight': 'bold'
                            },
                            'padding': 6,
                        }
                    },
                    'tooltips': {
                        'backgroundColor': '#f5f5f5',
                        'titleFontColor': '#333',
                        'bodyFontColor': '#666',
                        'bodySpacing': 4,
                        'xPadding': 12,
                        'mode': 'nearest',
                        'intersect': 0,
                    }
                }
            }
            return result
    
        def chart_data_line_prod(self, chart_data, scale):
            """
            Fonction retournant le dictionnaire permettant la construiction
            des graphes de la partie production
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
            if scale == 'day':
                offsetGridLines = False
            else:
                offsetGridLines = True
            result = {}
            result['line_chart_prod_line'] = {
                'type': 'line',
                'data': {
                    'labels': chart_data['label'],
                    'datasets': [
                        {
                            'label': 'AutoProd',
                            'data': chart_data['autocons_prod'],
                            'backgroundColor': 'rgba(91, 154, 81, 0.4)',
                            'borderColor': 'rgba(91, 154, 81, 1)',
                            'borderWidth': 2,
                            'hoverRadius': 1,
                            'radius': 0,
                            'fill': 'origin'
                        },
                        {
                            'label': 'Surplus',
                            'data': chart_data['surplus'],
                            'backgroundColor': 'rgba(225, 80, 96, 0.4)',
                            'borderColor': 'rgba(225, 80, 96, 1)',
                            'borderWidth': 2,
                            'hoverRadius': 1,
                            'radius': 0,
                            'fill': '-1'
                        },
                    ],
                },
                'options': {
                    'scales': {
                        'xAxes': [{
                            'type': 'time',
                            'time': {
                                'unit': scale,
                            },
                            'ticks': {
                                # 'min': result.date_start,
                            },
                            'gridLines': {
                                'offsetGridLines': offsetGridLines
                            }
                        }],
                        'yAxes': [{
                            'stacked': True,
                            'scaleLabel': {
                                'display': True,
                                'labelString': 'kW',
                            }
                        }]
                    },
                    'tooltips': {
                        'backgroundColor': '#f5f5f5',
                        'titleFontColor': '#333',
                        'bodyFontColor': '#666',
                        'bodySpacing': 4,
                        'xPadding': 12,
                        'mode': 'x',
                        'intersect': False,
                    },
                    'elements': {
                        'point': {
                            'radius': 0
                        }
                    },
                },
            }
            return result
    
        def chart_data_donuts_prod(self, chart_data, scale):
            """
            Fonction retournant le dictionnaire permettant la construction
            des graphes de la partie production
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
    
            result = {}
            if scale == 'hour':
                sum_res1 = sum(int(item['y']) for item in chart_data['autocons_prod'])
                sum_res2 = sum(int(item['y']) for item in chart_data['surplus'])
            else:
                sum_res1 = sum(chart_data['autocons_prod'])
                sum_res2 = sum(chart_data['surplus'])
    
            if sum_res1 == 0:
                label = ['Surplus']
                res = [sum_res2]
            elif sum_res2 == 0:
                label = ['AutoProd']
                res = [sum_res1]
            else:
                label = ['AutoProd', 'Surplus']
                res = [sum_res1, sum_res2]
    
            result['donuts_chart_prod'] = {
                'type': 'doughnut',
                'data': {
                    'labels': label,
                    'datasets': [{
                        'label': 'Inférieur à 3',
                        'data': res,
                        'backgroundColor': [
                            'rgba(91, 154, 81, 0.4)',
                            'rgba(225, 80, 96, 0.4)',
                        ],
                        'hoverBackgroundColor': [
                            'rgba(91, 154, 81, 0.7)',
                            'rgba(225, 80, 96, 0.7)',
                        ],
                        'borderWidth': 1
                    }],
                },
                'options': {
                    'plugins': {
                        'datalabels': {
                            'color': 'white',
                            'font': {
                                'weight': 'bold'
                            },
                            'padding': 6,
                        }
                    },
                    'cutoutPercentage': 60,
                    'animation': {
                        'animateScale': True,
                    },
                    'tooltips': {
                        'backgroundColor': '#f5f5f5',
                        'titleFontColor': '#333',
                        'bodyFontColor': '#666',
                        'bodySpacing': 4,
                        'xPadding': 12,
                        'mode': 'nearest',
                        'intersect': 0,
                    }
                }
            }
    
            return result
    
        def chart_data_histo_prod(self, chart_data, scale, scale_spe):
            """
            Fonction retournant le dictionnaire permettant la construiction
            des graphes de la partie production
            :param  chart_data: données à afficher dans les chart (labels et data)
            :return: un dictionnaire de chart
            """
    
            result = {}
            if scale_spe == 'week':
                data_autocons = chart_data['autocons_prod_histo']
                data_surplus = chart_data['surplus_histo']
                data_label = chart_data['label_histo']
            else:
                data_autocons = chart_data['autocons_prod']
                data_surplus = chart_data['surplus']
                data_label = chart_data['label']
    
            result['histo_chart_prod'] = {
                'type': 'bar',
                'data': {
                    'labels': data_label,
                    'datasets': [
                        {
                            'label': 'AutoProd',
                            'data': data_autocons,
                            'backgroundColor': 'rgba(91, 154, 81, 0.4)',
                            'hoverBackgroundColor': 'rgba(91, 154, 81, 0.7)',
                            'borderColor': 'rgba(91, 154, 81, 1)',
                        },
                        {
                            'label': 'Surplus',
                            'data': data_surplus,
                            'backgroundColor': 'rgba(225, 80, 96, 0.4)',
                            'hoverBackgroundColor': 'rgba(225, 80, 96, 0.7)',
                            'borderColor': 'rgba(225, 80, 96, 1)',
                        }]
                },
                'options': {
                    'plugins': {
                        'datalabels': {
                            'color': 'white',
                            'font': {
                                'weight': 'bold'
                            },
                        }
                    },
                    'interaction': {
                        'intersect': False,
                    },
                    'scales': {
                        'xAxes': [{
                            'type': 'time',
                            'time': {
                                'unit': scale
                            },
                            'stacked': True,
                            'offset': True,
                            'gridLines': {
                                'offsetGridLines': True
                            }
                        }],
                        'yAxes': [{
                            'stacked': True,
                            'ticks': {
                                'beginAtZero': True,
                            },
                            'type': 'linear',
                            'scaleLabel': {
                                'display': True,
                                'labelString': 'kWh',
                            }
                        }]
                    },
                    'tooltips': {
                        'backgroundColor': '#f5f5f5',
                        'titleFontColor': '#333',
                        'bodyFontColor': '#666',
                        'bodySpacing': 4,
                        'xPadding': 12,
                        'mode': 'nearest',
                        'intersect': 0,
                    },
                }
            }
    
            return result
    
        def get_cdc(self, scale, step_courbe, 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
            :param  step_courbe: Pas à prendre en courbe pour le calcul des courbes
                           (hour/day/week/month/year)
                    date_start: date début
                    date_end: date de fin
                    prm_ids: PRMs
            :return: un dictionnaire de données
                    (labels et data pour les charts à afficher)
            """
            chart_data = self.get_cdc_by_query(step_courbe, date_start, date_end, None)
    
            if scale == 'week':
                chart_data_histo = self.get_cdc_by_query_histo('day', date_start, date_end, None)
                chart_data.update(chart_data_histo)
    
            return chart_data
    
        @api.model
        def graph_view(self, domain, scale, first_day, last_day, acc_counter_id=None):
            """
            Fonction appelée lors du chargement de la vue Qweb
            :param  domain: représente le champ recherche de la vue
                    scale: type d'affichage des graphes
                           (day/week/month/semestre/year)
                            défini par le clic bouton
            :return: dictionnaire pour la construction des graphes
            """
            result_graph = {}
            # Get the operations depending to the domain
            operation_ids = self.env['acc.operation'].search(domain)
    
            if operation_ids:
                # Get date start and date end depending on type of scale
                if first_day and last_day:
                    date_start = fields.Datetime.to_datetime(first_day)
                    date_end = fields.Datetime.to_datetime(last_day)
                    date_end = date_utils.end_of(date_end, 'day')
                elif first_day:
                    date_start, date_end = operation_ids.get_last_day('day')
                    date_end = date_utils.end_of(date_end, 'day')
                else:
                    date_start, date_end = operation_ids.get_last_day('month')
                    date_end = date_utils.end_of(date_end, 'day')
    
                counter_ids = None
                if acc_counter_id:
                    counter_ids = self.env['acc.counter'].search([('name', '=', acc_counter_id)]).ids
    
                scale, step_courbe, step_display_courbe = operation_ids.get_step_from_date(
                    date_start=date_start, date_end=date_end, scale=scale)
                # Get the data to display in chart
                chart_data = operation_ids.get_cdc(scale=scale, step_courbe=step_courbe, date_start=date_start, date_end=date_end,
                                                   prm_ids=counter_ids)
    
                # Build the chart with data and options
                result_graph_line = self.chart_data_line_prod(chart_data, step_display_courbe)
                result_graph.update(result_graph_line)
                result_graph_histo = self.chart_data_histo_prod(chart_data, step_display_courbe, scale)
                result_graph.update(result_graph_histo)
                result_graph_donuts = self.chart_data_donuts_prod(chart_data, step_courbe)
                result_graph.update(result_graph_donuts)
    
                result_graph_line = self.chart_data_line_cons(chart_data, step_display_courbe)
                result_graph.update(result_graph_line)
                result_graph_histo = self.chart_data_histo_cons(chart_data, step_display_courbe, scale)
                result_graph.update(result_graph_histo)
                result_graph_donuts = self.chart_data_donuts_cons(chart_data, step_courbe)
                result_graph.update(result_graph_donuts)
    
                # result_graph.update(result_graph2)
                result_graph.update({'scale': scale})
    
                date_end = date_end.strftime("%d/%m/%Y")
                date_min = operation_ids.get_first_day()
                date_min = date_min.strftime("%d/%m/%Y")
                result_graph.update({
                    'date_end': date_end,
                    'date_min': date_min,
                    'date_start': date_start,
                })
    
            return result_graph
    
        # ------------------------------------------------------
        # Functions to manage route
        # ------------------------------------------------------
        def build_graph_data_options(self, chart_data, step_display_courbe=None, scale=None, step_courbe=None):
            result_graph = {}
            result_graph_line = self.chart_data_line_prod(chart_data, step_display_courbe)
            result_graph.update(result_graph_line)
            result_graph_histo = self.chart_data_histo_prod(chart_data, step_display_courbe, scale)
            result_graph.update(result_graph_histo)
            result_graph_donuts = self.chart_data_donuts_prod(chart_data, step_courbe)
            result_graph.update(result_graph_donuts)
    
            result_graph_line = self.chart_data_line_cons(chart_data, step_display_courbe)
            result_graph.update(result_graph_line)
            result_graph_histo = self.chart_data_histo_cons(chart_data, step_display_courbe, scale)
            result_graph.update(result_graph_histo)
            result_graph_donuts = self.chart_data_donuts_cons(chart_data, step_courbe)
            result_graph.update(result_graph_donuts)
            return result_graph
    
        def build_graph_data_options_prod(self, chart_data, step_display_courbe=None, scale=None, step_courbe=None):
            result_graph = {}
            result_graph_line = self.chart_data_line_prod(chart_data, step_display_courbe)
            result_graph.update(result_graph_line)
            result_graph_histo = self.chart_data_histo_prod(chart_data, step_display_courbe, scale)
            result_graph.update(result_graph_histo)
            result_graph_donuts = self.chart_data_donuts_prod(chart_data, step_courbe)
            result_graph.update(result_graph_donuts)
            return result_graph
    
        def build_graph_data_options_cons(self, chart_data, step_display_courbe=None, scale=None, step_courbe=None):
            result_graph = {}
            result_graph_line = self.chart_data_line_cons(chart_data, step_display_courbe)
            result_graph.update(result_graph_line)
            result_graph_histo = self.chart_data_histo_cons(chart_data, step_display_courbe, scale)
            result_graph.update(result_graph_histo)
            result_graph_donuts = self.chart_data_donuts_cons(chart_data, step_courbe)
            result_graph.update(result_graph_donuts)
            return result_graph
    
        # ------------------------------------------------------
        # Functions to manage route
        # ------------------------------------------------------
        def graph_view_global(self, scale=None, date_start=None, date_end=None):
            """
            Fonction appelée pour l'affichage des courbes consommation
            sur le portail
            :param  scale: type d'affichage des graphes
                           (day/week/month/semestre/year)
                            défini par le clic bouton
            :return: dictionnaire pour la construction des graphes
            """
    
            result_graph = {}
            if not date_start and not date_end:
                date_start, date_end = self.get_last_day(scale)
            else:
                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=scale)
            # Get the data to display in chart
            chart_data = self.get_cdc(
                scale=scale, step_courbe=step_courbe, date_start=date_start,
                date_end=date_end, prm_ids=None)
    
            # Build the chart with data and options
            result_graph = self.build_graph_data_options(
                chart_data, step_display_courbe=step_display_courbe, scale=scale, step_courbe=step_courbe)
    
            date_deb, date_max = self.get_last_day('day')
            date_max = date_max.strftime("%d/%m/%Y")
            date_min = self.get_first_day()
            date_min = date_min.strftime("%d/%m/%Y")
    
            result_graph.update({
                'date_start': date_start,
                'date_end': date_end,
                'date_min': date_min,
                'date_max': date_max,
                'scale': scale
            })
            return result_graph
    
        # ------------------------------------------------------
        # Functions to manage route
        # ------------------------------------------------------
        def graph_view_type(self, type=None, scale=None, date_start=None, date_end=None, prm_id=None, partner_id=None):
            """
            Fonction appelée pour l'affichage des courbes consommation
            sur le portail
            :param  scale: type d'affichage des graphes
                           (day/week/month/semestre/year)
                            défini par le clic bouton
            :return: dictionnaire pour la construction des graphes
            """
    
            result_graph = {}
            if not date_start and not date_end:
                date_start, date_end = self.get_last_day(scale)
            else:
                date_end = date_utils.end_of(date_end, 'day')
    
            # Get the step to display curve in chart
            scale, step_courbe, step_display_courbe = self.get_step_from_date(
                date_start=date_start, date_end=date_end, scale=scale)
    
            # 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:
                if type == 'cons':
                    acc_counter_ids = self.acc_delivery_ids
                else:
                    acc_counter_ids = self.acc_injection_ids
    
            if type == 'cons':
                chart_data = self.get_cdc_by_query_cons(step_courbe, 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)
                    chart_data.update(chart_data_histo)
    
                # Build the chart with data and options
                result_graph = self.build_graph_data_options_cons(chart_data, step_display_courbe=step_display_courbe,
                                                                 scale=scale, step_courbe=step_courbe)
            else:
                chart_data = self.get_cdc_by_query_prod(step_courbe, 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)
                    chart_data.update(chart_data_histo)
    
                # Build the chart with data and options
                result_graph = self.build_graph_data_options_prod(chart_data, step_display_courbe=step_display_courbe,
                                                                  scale=scale, step_courbe=step_courbe)
            date_deb, date_max = self.get_last_day('day')
            date_max = date_max.strftime("%d/%m/%Y")
            date_min = self.get_first_day()
            date_min = date_min.strftime("%d/%m/%Y")
    
            result_graph.update({
                'date_start': date_start,
                'date_end': date_end,
                'date_min': date_min,
                'date_max': date_max,
                'scale': scale
            })
            return result_graph