diff --git a/models/acc_operation.py b/models/acc_operation.py index 9adba58d1a4995b3a3d4314aa58dc95a3d8ada13..39356ab1269a6daf56864553b0d0697153f5c9e2 100644 --- a/models/acc_operation.py +++ b/models/acc_operation.py @@ -5,7 +5,7 @@ from datetime import datetime, time from dateutil.relativedelta import relativedelta from odoo import _, models -from odoo.exceptions import UserError, ValidationError +from odoo.exceptions import ValidationError from odoo.osv import expression from odoo.tools import date_utils @@ -46,36 +46,18 @@ class AccOperation(models.Model): last_record = self.get_last_cdc_record() start_date, end_date = self.get_interval("month", last_record) end_date_month = end_date + relativedelta(days=1) - query = """ - SELECT - date_trunc('month', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') AS date_slot, - (SUM( (CASE - WHEN cdc.comp_data_type = 'cons' THEN cdc.power - ELSE 0 END) )/2) / 1000 as conso_tot, - (SUM( (CASE - WHEN cdc.comp_data_type = 'prod' - THEN cdc.power ELSE 0 END) )/2) / 1000 as prod_tot, - (SUM( (CASE WHEN - cdc.comp_data_type = 'autocons' THEN cdc.power - ELSE 0 END) )/2) / 1000 as autoconso_tot - FROM - acc_enedis_cdc cdc - INNER JOIN acc_operation ope - ON ope.id = cdc.acc_operation_id - WHERE - cdc.acc_operation_id = %s - AND cdc.date_slot >= %s - AND cdc.date_slot < %s - GROUP BY date_trunc('month', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris'); - """ - query_params = ( - self.id, - self._convert_time(start_date), - self._convert_time(end_date_month), + query = ( + self._select_clause("month", ["cons", "prod", "autocons"]) + + self._from_clause() + + self._where_clause( + self.id, + self._convert_time(start_date), + self._convert_time(end_date_month), + ) + + self._group_clause("month") + + self._order_clause() ) - self.env.cr.execute(query, query_params) + self.env.cr.execute(query) raw_data = self.env.cr.fetchone() return raw_data[1], raw_data[2], raw_data[3], start_date @@ -161,7 +143,7 @@ class AccOperation(models.Model): step = "hour" step_display_curve = "hour" # Calculate delta between 2 dates - delta = (self._convert_time(end_date) - self._convert_time(start_date)).days + delta = (end_date - start_date).days if delta > 0 and delta < 31: step_display_curve = "day" display_hourly_curves = True @@ -174,22 +156,145 @@ class AccOperation(models.Model): return display_hourly_curves, step, step_display_curve + def _select_clause(self, date_slot, curve_types): + """ + Function to build SELECT section of query for retrieving curves + @param + char date_slot : granularity (one of "hour", "day", "month", "year") + [char] curve_types : list of type of curves + (allowed values : 'cons', 'autocons', 'allocons', + 'prod', 'surplus', 'autoprod') + """ + if date_slot not in ("hour", "day", "month", "year"): + raise ValidationError(_("Incorrect date_slot in SELECT section")) + result = f""" + SELECT date_trunc('{date_slot}', + cdc.date_slot AT TIME ZONE 'UTC' AT TIME ZONE 'Europe/Paris' + ) AS date_slot + """ + for curve_type in curve_types: + if curve_type in ("cons", "autocons", "prod", "surplus"): + result += f""" + , (SUM(CASE WHEN cdc.comp_data_type = '{curve_type}' + THEN cdc.power ELSE 0 END)) /2 / 1000 as {curve_type} + """ + elif curve_type == "allocons": + result += """ + ,(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 + """ + elif curve_type == "autoprod": + result += """ + ,(SUM(CASE + WHEN cdc.comp_data_type = 'prod' + THEN cdc.power ELSE 0 END) + - SUM(CASE + WHEN cdc.comp_data_type = 'surplus' + THEN cdc.power ELSE 0 END)) / 2 / 1000 as autoprod + """ + return result + + def _from_clause(self): + """ + Function to build FROM section of query for retrieving curves + """ + return """ + FROM + acc_enedis_cdc cdc + INNER JOIN acc_operation ope + ON ope.id = cdc.acc_operation_id + """ + + def _where_clause( + self, + operation_id, + start_date, + end_date, + prm_id=None, + extra_curve_type=None, + partner_id=None, + ): + """ + Function to build WHERE section of query for retrieving curves + @param + int operation_id : id of operation for which curves should be retrieved + datetime start_date : first datetime to be retrieved + datetime end_date : last datetime to be retrieved + int prm_id : id of PRM to be retrieved (optional) + char extra_curve_type : extra curve to be retrieved (optional) + (allowed values : 'cons', 'autocons', 'allocons', + 'prod', 'surplus', 'autoprod') + int partner_id : id of partner to be retrieved (optional) + """ + if ( + not isinstance(operation_id, int) + and not isinstance(start_date, datetime) + and not isinstance(end_date, datetime) + ): + raise ValidationError(_("WHERE clause parameters incorrect")) + result = f""" + WHERE cdc.acc_operation_id = {operation_id} + AND cdc.date_slot >= '{start_date}' + AND cdc.date_slot < '{end_date}' + """ + if prm_id and isinstance(prm_id, int): + if extra_curve_type and extra_curve_type in ( + "cons", + "autocons", + "allocons", + "prod", + "surplus", + "autoprod", + ): + result += f""" + AND (cdc.comp_data_type = {extra_curve_type} + OR cdc.acc_counter_id = {prm_id}) + """ + else: + result += f""" + AND cdc.acc_counter_id = {prm_id} + """ + if partner_id and isinstance(partner_id, int): + result += f" AND cdc.partner_id = {partner_id}" + return result + + def _group_clause(self, date_slot): + """ + Function to build GROUP BY section of query for retrieving curves + @param + char date_slot : granularity (one of "hour", "day", "month", "year") + """ + if date_slot not in ("hour", "day", "month", "year"): + raise ValidationError(_("Incorrect date_slot in GROUP BY section")) + return f""" + GROUP BY date_trunc('{date_slot}', + cdc.date_slot AT TIME ZONE 'UTC' AT TIME ZONE 'Europe/Paris') + """ + + def _order_clause(self): + return "ORDER BY date_slot ASC;" + def get_cdc_by_query_cons( - self, slot_type, start_date, end_date, prm_ids=None, partner_ids=None + self, slot_type, start_date, end_date, prm_id=None, partner_id=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 ("hour", "month" ou + :param: char slot_type: type de slot pour la query ("hour", "month" ou "year") - start_date: date début - end_date: date de fin - prm_ids : liste des PRMs de soutirage à récupérer - partner_ids: liste des partner associés à la courbe + datetime start_date: date début + datetime end_date: date de fin + int prm_id : PRM de soutirage à récupérer + int partner_id: contact associé à la courbe @returns: un dictionnaire de données (labels et data pour les charts à afficher) """ + self.ensure_one() label = [] data_autocons = [] @@ -197,43 +302,17 @@ class AccOperation(models.Model): data_cons = [] data_prod = [] - query = """ - SELECT - date_trunc(%s, cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') AS date_slot, - (SUM( (CASE - WHEN cdc.comp_data_type = 'cons' - THEN cdc.power ELSE 0 END) )/2) / 1000 as cons, - (SUM( (CASE - 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 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 OR cdc.comp_data_type = 'prod' ) - AND cdc.date_slot >= %s - AND cdc.date_slot <= %s - AND cdc.partner_id IN %s - GROUP BY date_trunc(%s, cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') - ORDER BY date_slot ASC; - """ - query_params = ( - slot_type, - tuple(self.ids), - tuple(prm_ids.ids), - start_date, - end_date, - tuple(partner_ids.ids), - slot_type, + query = ( + self._select_clause(slot_type, ["cons", "autocons", "prod"]) + + self._from_clause() + + self._where_clause( + self.id, start_date, end_date, prm_id, "prod", partner_id + ) + + "AND cdc.comp_data_type IN ('autocons', 'cons', 'prod')" + + self._group_clause(slot_type) + + self._order_clause() ) - self.env.cr.execute(query, query_params) + self.env.cr.execute(query) raw_data = self.env.cr.fetchall() for row in raw_data: label.append(row[0]) @@ -252,15 +331,15 @@ class AccOperation(models.Model): return cdc_cons def get_cdc_by_query_daily_histo_cons( - self, start_date, end_date, prm_ids=None, partner_ids=None + self, start_date, end_date, prm_id=None, partner_id=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: start_date: date début - end_date: date de fin - prm_ids: liste des PRMs de soutirage à récupérer - partner_ids: liste des partner associés à la courbe + :param: datetime start_date: date début + datetime end_date: date de fin + int prm_id : PRM de soutirage à récupérer + int partner_id: contact associé à la courbe :return: un dictionnaire de données (labels et data pour les charts à afficher) """ @@ -268,39 +347,15 @@ class AccOperation(models.Model): data_autocons_histo = [] data_allocons_histo = [] - query = """ - SELECT - date_trunc('day', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') AS date_slot, - (SUM( (CASE - 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 - AND cdc.partner_id IN %s - GROUP BY date_trunc('day', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') - ORDER BY date_slot ASC; - """ - query_params = ( - tuple(self.ids), - tuple(prm_ids.ids), - start_date, - end_date, - tuple(partner_ids.ids), + query = ( + self._select_clause("day", ["autocons", "allocons"]) + + self._from_clause() + + self._where_clause(self.id, start_date, end_date, prm_id, partner_id) + + self._group_clause("day") + + self._order_clause() ) - self.env.cr.execute(query, query_params) + + self.env.cr.execute(query) raw_data = self.env.cr.fetchall() for row in raw_data: data_autocons_histo.append(round(row[1], 2)) @@ -315,17 +370,17 @@ class AccOperation(models.Model): return cdc_cons def get_cdc_by_query_prod( - self, slot_type, start_date, end_date, prm_ids=None, partner_ids=None + self, slot_type, start_date, end_date, prm_id=None, partner_id=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 ("hour", "month" - ou "year") - start_date: date début - end_date: date de fin - prm_ids: liste des PRMs d'injection à récupérer - partner_ids: liste des partner associés à la courbe + :param: char slot_type: type de slot pour la query ("hour", "month" ou + "year") + datetime start_date: date début + datetime end_date: date de fin + int prm_id : PRM d'injection à récupérer + int partner_id: contact associé à la courbe :return: un dictionnaire de données (labels et data pour les charts à afficher) """ @@ -333,42 +388,15 @@ class AccOperation(models.Model): data_autocons = [] data_surplus = [] - query = """ - SELECT - date_trunc(%s, cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') AS date_slot, - ((SUM((CASE - WHEN cdc.comp_data_type = 'prod' THEN cdc.power - ELSE 0 END)) - - SUM(CASE - WHEN cdc.comp_data_type = 'surplus' THEN cdc.power - ELSE 0 END)) / 2) / 1000 as autocons, - (SUM( (CASE - WHEN cdc.comp_data_type = 'surplus' THEN cdc.power - ELSE 0 END) )/2) / 1000 as surplus - 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 - AND cdc.partner_id IN %s - GROUP BY date_trunc(%s, cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') - ORDER BY date_slot ASC; - """ - query_params = ( - slot_type, - tuple(prm_ids.ids), - tuple(self.ids), - start_date, - end_date, - tuple(partner_ids.ids), - slot_type, + query = ( + self._select_clause(slot_type, ["autoprod", "surplus"]) + + self._from_clause() + + self._where_clause(self.id, start_date, end_date, prm_id, partner_id) + + self._group_clause(slot_type) + + self._order_clause() ) - self.env.cr.execute(query, query_params) + + self.env.cr.execute(query) raw_data = self.env.cr.fetchall() for row in raw_data: label.append(row[0]) @@ -383,15 +411,15 @@ class AccOperation(models.Model): return cdc_prod def get_cdc_by_query_daily_histo_prod( - self, start_date, end_date, prm_ids=None, partner_ids=None + self, start_date, end_date, prm_id=None, partner_id=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: start_date: date début - end_date: date de fin - prm_ids: liste des PRMs d'injection à récupérer - partner_ids: liste des partner associés à la courbe + :param: datetime start_date: date début + datetime end_date: date de fin + int prm_id : PRM d'injection à récupérer + int partner_id: contact associé à la courbe :return: un dictionnaire de données (labels et data pour les charts à afficher) """ @@ -399,40 +427,14 @@ class AccOperation(models.Model): data_autocons_prod_histo = [] data_surplus_histo = [] - query = """ - SELECT - date_trunc('day', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') AS date_slot, - ((SUM((CASE - WHEN cdc.comp_data_type = 'prod' THEN cdc.power - ELSE 0 END)) - - SUM(CASE - WHEN cdc.comp_data_type = 'surplus' THEN cdc.power - ELSE 0 END)) / 2) / 1000 as autocons, - (SUM( (CASE - WHEN cdc.comp_data_type = 'surplus' THEN cdc.power - ELSE 0 END) )/2) / 1000 as surplus - 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 - AND cdc.partner_id IN %s - GROUP BY date_trunc('day', cdc.date_slot AT TIME ZONE 'UTC' \ - AT TIME ZONE 'Europe/Paris') - ORDER BY date_slot ASC; - """ - query_params = ( - tuple(prm_ids.ids), - tuple(self.ids), - start_date, - end_date, - tuple(partner_ids.ids), + query = ( + self._select_clause("day", ["autoprod", "surplus"]) + + self._from_clause() + + self._where_clause(self.id, start_date, end_date, prm_id, partner_id) + + self._group_clause("day") + + self._order_clause() ) - self.env.cr.execute(query, query_params) + self.env.cr.execute(query) raw_data = self.env.cr.fetchall() for row in raw_data: label_histo.append(row[0]) @@ -475,7 +477,7 @@ class AccOperation(models.Model): """ Fonction appelée pour l'affichage des courbes globales sur le portail - :param: start_date: date début + :param: start_date: date début end_date: date de fin partner_id: données uniquement de ce contact prm_id: données uniquement de ce PRM (mutuellement exclusif de @@ -488,51 +490,32 @@ class AccOperation(models.Model): """ self.ensure_one() result_graph = {} - start_date = self._convert_time(datetime.strptime(start_date, "%d/%m/%Y")) - end_date = self._convert_time( - datetime.combine(datetime.strptime(end_date, "%d/%m/%Y"), time.max) - ) + start_date = datetime.strptime(start_date, "%d/%m/%Y") + end_date = datetime.combine(datetime.strptime(end_date, "%d/%m/%Y"), time.max) display_hourly_curves, step_curve, step_display_curve = self.get_step_from_date( start_date=start_date, end_date=end_date ) - - domain = [["acc_operation_id", "=", self.id]] - - if prm_id: - domain = expression.AND([domain, [("acc_counter_id", "=", prm_id)]]) - if partner_id: - domain = expression.AND([domain, [("partner_id", "=", partner_id)]]) - periods = ( - self.env["acc.counter.period"] - .sudo() - ._get_periods_from_interval( - domain=domain, start_date=start_date, end_date=end_date - ) - ) - if periods: - acc_counter_ids = periods.mapped("acc_counter_id") - acc_partner_ids = periods.mapped("partner_id") - else: - raise UserError(_("No data found")) + start_datetime = self._convert_time(start_date) + end_datetime = self._convert_time(end_date) chart_data = {} if data_type == "cons" or data_type == "pmo": chart_data_cons = self.get_cdc_by_query_cons( - step_curve, start_date, end_date, acc_counter_ids, acc_partner_ids + step_curve, start_datetime, end_datetime, prm_id, partner_id ) if display_hourly_curves: chart_data_histo = self.get_cdc_by_query_daily_histo_cons( - start_date, end_date, acc_counter_ids, acc_partner_ids + start_datetime, end_datetime, prm_id, partner_id ) 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_curve, start_date, end_date, acc_counter_ids, acc_partner_ids + step_curve, start_datetime, end_datetime, prm_id, partner_id ) if display_hourly_curves: chart_data_histo = self.get_cdc_by_query_daily_histo_prod( - start_date, end_date, acc_counter_ids, acc_partner_ids + start_datetime, end_datetime, prm_id, partner_id ) chart_data_prod.update(chart_data_histo) chart_data.update(chart_data_prod)