Sélectionner une révision Git
scop_address_wizard.py
enercoop_operation.py 30,74 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
import dateutil.parser as parser
from dateutil.relativedelta import relativedelta
class EnercoopOperation(models.Model):
_inherit = 'enercoop.operation'
# ------------------------------------------------------
# Fields declaration
# ------------------------------------------------------
# ------------------------------------------------------
# SQL Constraints
# ------------------------------------------------------
# ------------------------------------------------------
# Default methods
# ------------------------------------------------------
# ------------------------------------------------------
# Computed fields / Search Fields
# ------------------------------------------------------
# ------------------------------------------------------
# Onchange / Constraints
# ------------------------------------------------------
# ------------------------------------------------------
# CRUD methods (ORM overrides)
# ------------------------------------------------------
@api.model
def graph_view(self, domain, scale):
"""
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['enercoop.operation'].search(domain)
if operation_ids:
# # Get date start and date end depending on type of scale if scale fill
# if scale:
# date_start, date_end = self.get_last_day(scale)
#
# # Get scale depending on the date start and date end
# if date_start and date_end:
# scale = self.get_scale(date_start, date_end)
# Get date start and date end depending on type of scale
date_start, date_end = operation_ids.get_last_day(scale)
# Get the data to display in chart
chart_data = operation_ids.get_cdc(type=scale, date_start=date_start, date_end=date_end)
# Build the chart depending on data calculated
result_graph = operation_ids.chart_data_cons(chart_data)
result_graph_prod = operation_ids.chart_data_prod(chart_data)
result_graph.update(result_graph_prod)
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
})
return result_graph
# ------------------------------------------------------
# Actions
# ------------------------------------------------------
def action_view_courbes(self):
"""
Action qui ouvre la vue Qweb
:return: Vue Qweb
"""
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id(
"enercoop_cdc.enercoop_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_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['enercoop.enedis.cdc'].search([
('enercoop_operation_id', 'in', self.ids),
], limit=1, order='date_slot DESC')
date_end = last_record.date_slot
if scale == 'day':
date_build = str(last_record.date_slot.year) + '-' + str(last_record.date_slot.month) + '-' + str(
last_record.date_slot.day) + 'T00:00:00'
date_start = datetime.strptime(date_build, "%Y-%m-%dT%H:%M:%S")
date_end = date_start + timedelta(days=1)
elif scale == 'week':
date_start = date_end + timedelta(weeks=-1)
elif scale == 'semestre':
date_start = date_end - relativedelta(months=6)
elif scale == 'year':
date_start = date_end - relativedelta(years=1)
else:
date_start = date_end - relativedelta(months=1)
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['enercoop.enedis.cdc'].search([
('enercoop_operation_id', 'in', self.ids),
], limit=1, order='date_slot ASC')
date_min = first_record.date_slot
return date_min
def get_scale(self, date_start, date_end):
"""
Fonction retournant l'échelle à appliquer en fonction d'une date de début et une date de fin.
:return: scale: day/week/month/semestre/year
"""
# Calculate delta between 2 dates
if date_start == date_end:
scale = 'day'
return scale
else:
delta = (date_end - date_start).days
if delta <= 7:
scale = 'week'
elif delta <= 31:
scale = 'month'
elif delta <= 180:
scale = 'semestre'
else:
scale = 'year'
return scale
def chart_data_cons(self, chart_data):
"""
Fonction retournant le dictionnaire permettant la construiction
des graphes de la partie consommation
:param chart_data: données à afficher dans les chart (labels et data)
:return: un dictionnaire de chart
"""
result = {}
result['line_chart_conso'] = {
'type': 'line',
'data': {
'labels': chart_data['label'],
'datasets': [
{
'label': 'Allo Conso',
'data': chart_data['cons'],
'backgroundColor': 'rgba(57, 120, 187, 0.7)',
'borderColor': 'rgba(57, 120, 187, 1)',
},
{
'label': 'Production solaire',
'data': chart_data['prod'],
'backgroundColor': 'rgba(244, 165, 25, 0)',
'borderColor': 'rgba(244, 165, 25, 1)',
},
{
'label': 'Autoconso',
'data': chart_data['autocons'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
],
},
}
result['line_chart_conso_line'] = {
'type': 'line',
'data': {
'labels': chart_data['label'],
'datasets': [
{
'label': 'Allo Conso',
'data': chart_data['cons_line'],
'backgroundColor': 'rgba(57, 120, 187, 0.7)',
'borderColor': 'rgba(57, 120, 187, 1)',
},
{
'label': 'Production solaire',
'data': chart_data['prod_line'],
'backgroundColor': 'rgba(244, 165, 25, 0)',
'borderColor': 'rgba(244, 165, 25, 1)',
},
{
'label': 'Autoconso',
'data': chart_data['autocons_line'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
],
},
}
result['donuts_chart_conso'] = {
'type': 'doughnut',
'data': {
'labels': chart_data['label_doughnut'],
'datasets': [{
'label': 'Inférieur à 3',
'data': chart_data['doughnut_cons'],
'backgroundColor': [
'rgb(91, 154, 81)',
'rgb(57, 120, 187)',
],
'borderWidth': 1
}],
},
}
result['histo_chart_conso'] = {
'type': 'bar',
'data': {
'labels': chart_data['label_histo'],
'datasets': [
{
'label': 'AutoConso',
'data': chart_data['autocons'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
{
'label': 'AlloConso',
'data': chart_data['cons'],
'backgroundColor': 'rgba(57, 120, 187, 0.7)',
'borderColor': 'rgba(57, 120, 187, 1)',
}]
}
}
return result
def chart_data_prod(self, chart_data):
"""
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 = {}
result['line_chart_prod']= {
'type': 'line',
'data': {
'labels': chart_data['label'],
'datasets': [
{
'label': 'Surplus',
'data': chart_data['surplus'],
'backgroundColor': 'rgba(225, 80, 96, 0.7)',
'borderColor': 'rgba(225, 80, 96, 1)',
},
{
'label': 'Autoconso',
'data': chart_data['autocons'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
],
},
}
result['line_chart_prod_line'] = {
'type': 'line',
'data': {
'labels': chart_data['label'],
'datasets': [
{
'label': 'Surplus',
'data': chart_data['surplus_line'],
'backgroundColor': 'rgba(225, 80, 96, 0.7)',
'borderColor': 'rgba(225, 80, 96, 1)',
},
{
'label': 'Autoconso',
'data': chart_data['autocons_line'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
],
},
}
result['donuts_chart_prod'] = {
'type': 'doughnut',
'data': {
'labels': chart_data['label_doughnut_prod'],
'datasets': [{
'label': 'Inférieur à 3',
'data': chart_data['doughnut_prod'],
'backgroundColor': [
'rgb(91, 154, 81)',
'rgb(225, 80, 96)',
],
'borderWidth': 1
}],
},
}
result['histo_chart_prod'] = {
'type': 'bar',
'data': {
'labels': chart_data['label_histo'],
'datasets': [
{
'label': 'AutoConso',
'data': chart_data['autocons'],
'backgroundColor': 'rgba(91, 154, 81, 0.7)',
'borderColor': 'rgba(91, 154, 81, 1)',
},
{
'label': 'Surplus',
'data': chart_data['surplus'],
# 'backgroundColor': 'rgba(192, 80, 77, 0.7)',
'backgroundColor': 'rgba(225, 80, 96, 0.7)',
'borderColor': 'rgba(225, 80, 96, 1)',
}]
}
}
return result
def get_cdc(self, type, date_start, date_end, prm_id=None):
"""
Fonction permettant de récupérer les données pour la
construction des chart pour une ou des opérations données
:param type: type d'affichage des graphes
(day/week/month/semestre/year)
date_start: date début
date_end: date de fin
:return: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
cdc_jour = []
label_line_cons = []
label_histo_cons = []
data_autocons = []
data_autocons_line = []
data_cons = []
data_cons_line = []
data_prod = []
data_prod_line = []
data_surplus = []
data_surplus_line = []
# Depending on type scale, define the date slot type
# Data by day / hour for type = day
# Data by week / day for type = week
# Data by month / day for type = month
# Data by year / months for type = year
if type == 'day':
type_date = 'date_slot:hour'
type_date_abs = 'date_slot:day'
type_date_histo = 'date_slot:hour'
elif type == 'year':
type_date = 'date_slot:month'
type_date_abs = 'date_slot:month'
type_date_histo = 'date_slot:month'
else:
type_date = 'date_slot:day'
type_date_abs = 'date_slot:day'
type_date_histo = 'date_slot:day'
if type == 'week':
type_date = 'date_slot:hour'
enercoop_counter_id = self.env['enercoop.counter']
if prm_id:
enercoop_counter_id = self.env['enercoop.counter'].browse(prm_id)
if enercoop_counter_id:
# Get all data group by curves type and date
cdc_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
'|', ('enercoop_counter_id', '=', False), ('enercoop_counter_id', '=', enercoop_counter_id.id)
],
['power', 'enercoop_operation_id', 'date_slot'],
['comp_data_type', type_date], orderby='comp_data_type, date_slot ASC', lazy=False)
if type == 'week':
cdc_histo_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
'|', ('enercoop_counter_id', '=', False), ('enercoop_counter_id', '=', enercoop_counter_id.id)
],
['power', 'enercoop_operation_id', 'date_slot'],
['comp_data_type', type_date_histo], orderby='comp_data_type, date_slot ASC', lazy=False)
# Get the date for the abscissa axis
cdc_date_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
'|', ('enercoop_counter_id', '=', False), ('enercoop_counter_id', '=', enercoop_counter_id.id)
],
['enercoop_operation_id', 'date_slot'],
[type_date_abs], orderby='date_slot ASC', lazy=False)
# Get the date for the abscissa axis (histo)
if type == 'day':
cdc_date_histo_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
'|', ('enercoop_counter_id', '=', False), ('enercoop_counter_id', '=', enercoop_counter_id.id)
],
['enercoop_operation_id', 'date_slot'],
[type_date], orderby='date_slot ASC', lazy=False)
else:
# Get all data group by curves type and date
cdc_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>=', date_start),
('date_slot', '<', date_end)
],
['power', 'enercoop_operation_id', 'date_slot'],
['comp_data_type', type_date], orderby='comp_data_type, date_slot ASC', lazy=False)
if type == 'week':
cdc_histo_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end)
],
['power', 'enercoop_operation_id', 'date_slot'],
['comp_data_type', type_date_histo], orderby='comp_data_type, date_slot ASC', lazy=False)
# Get the date for the abscissa axis
cdc_date_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
],
['enercoop_operation_id', 'date_slot'],
[type_date_abs], orderby='date_slot ASC', lazy=False)
# Get the date for the abscissa axis (histo)
if type == 'day':
cdc_date_histo_ids = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
],
['enercoop_operation_id', 'date_slot'],
[type_date], orderby='date_slot ASC', lazy=False)
# Build the abscissa axis with the right format date
for cdc in cdc_date_ids:
value_hour = cdc[type_date_abs]
label_line_cons.append(value_hour)
label_histo_cons.append(value_hour)
# Build the abscissa axis with the right format date (histo)
if type == 'day':
label_histo_cons = []
for cdc in cdc_date_histo_ids:
value_hour = cdc[type_date]
label_histo_cons.append(value_hour)
# Build the ordinate axis for each data type (autoconso/conso/prod/surplus)
for cdc in cdc_ids:
if type == 'day' or type == 'week':
value_power = round((cdc['power'] / 2), 2)
else:
value_power = round((cdc['power'] / 1000 / 2), 2)
if cdc['comp_data_type'] == 'autocons':
data_autocons.append(value_power)
if cdc['comp_data_type'] == 'cons':
data_cons.append(value_power)
if cdc['comp_data_type'] == 'prod':
data_prod.append(value_power)
if cdc['comp_data_type'] == 'surplus':
data_surplus.append(value_power)
# Build the ordinate axis for each data type (autoconso/conso/prod/surplus) for histo graph
if type == 'week':
data_autocons = []
data_cons = []
data_prod = []
data_surplus = []
for cdc in cdc_histo_ids:
value_power = round((cdc['power'] / 2), 2)
if cdc['comp_data_type'] == 'autocons':
data_autocons.append(value_power)
if cdc['comp_data_type'] == 'cons':
data_cons.append(value_power)
if cdc['comp_data_type'] == 'prod':
data_prod.append(value_power)
if cdc['comp_data_type'] == 'surplus':
data_surplus.append(value_power)
if type == 'day' or type == 'week':
if enercoop_counter_id:
query = """
SELECT
A.comp_data_type AS comp_data_type,
A.date_slot AS date_slot,
SUM(A.power) AS power
FROM enercoop_enedis_cdc A
JOIN enercoop_operation E ON E.id = A.enercoop_operation_id
WHERE A.enercoop_operation_id IS NOT NULL
AND A.enercoop_operation_id IN %s
AND ( A.enercoop_counter_id = %s
OR A.enercoop_counter_id = NULL )
AND A.date_slot > %s
AND A.date_slot < %s
GROUP BY A.comp_data_type, A.date_slot
ORDER BY A.comp_data_type, A.date_slot ASC;
"""
query_params = (tuple(self.ids), enercoop_counter_id.id, date_start, date_end)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.dictfetchall()
else:
query = """
SELECT
A.comp_data_type AS comp_data_type,
A.date_slot AS date_slot,
SUM(A.power) AS power
FROM enercoop_enedis_cdc A
JOIN enercoop_operation E ON E.id = A.enercoop_operation_id
WHERE A.enercoop_operation_id IS NOT NULL
AND A.enercoop_operation_id IN %s
AND A.date_slot > %s
AND A.date_slot < %s
GROUP BY A.comp_data_type, A.date_slot
ORDER BY A.comp_data_type, A.date_slot ASC;
"""
query_params = (tuple(self.ids), date_start, date_end)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.dictfetchall()
for cdc in raw_data:
if type == 'week' or type == 'day':
value_power = round((cdc['power']), 2)
value_hour = cdc['date_slot']
if cdc['comp_data_type'] == 'autocons':
data_autocons_line.append({'t': value_hour, 'y': value_power})
if cdc['comp_data_type'] == 'cons':
data_cons_line.append({'t': value_hour, 'y': value_power})
if cdc['comp_data_type'] == 'prod':
data_prod_line.append({'t': value_hour, 'y': value_power})
if cdc['comp_data_type'] == 'surplus':
data_surplus_line.append({'t': value_hour, 'y': value_power})
# Get the data to build the chart Bilan
if enercoop_counter_id:
bilan_cdc = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end),
'|', ('enercoop_counter_id', '=', False), ('enercoop_counter_id', '=', enercoop_counter_id.id)],
['power', 'enercoop_operation_id'],
['comp_data_type'], orderby='comp_data_type', lazy=False)
else:
bilan_cdc = self.env['enercoop.enedis.cdc'].sudo().read_group(
[('enercoop_operation_id', 'in', self.ids),
('date_slot', '>', date_start),
('date_slot', '<', date_end)],
['power', 'enercoop_operation_id'],
['comp_data_type'], orderby='comp_data_type', lazy=False)
# Build the ordinate axis for each data type (autoconso/conso/prod/surplus)
for bilan in bilan_cdc:
if bilan['comp_data_type'] == 'autocons':
power_autocons = bilan['power'] / 1000 / 2
if bilan['comp_data_type'] == 'cons':
power_cons = bilan['power'] / 1000 / 2
if bilan['comp_data_type'] == 'surplus':
power_surplus = bilan['power'] / 1000 / 2
if bilan['comp_data_type'] == 'prod':
power_prod = bilan['power'] / 1000 / 2
power_tot = power_autocons + power_cons
if power_tot > 0:
percent_autocons = round(power_autocons * 100 / power_tot, 2)
percent_cons = round(power_cons * 100 / power_tot, 2)
else:
percent_autocons = round(power_autocons * 100, 2)
percent_cons = round(power_cons * 100, 2)
power_prod_tot = power_autocons + power_surplus
if power_prod_tot > 0:
percent_autocons_prod = round(power_autocons * 100 / power_prod_tot, 2)
percent_surplus_prod = round(power_surplus * 100 / power_prod_tot, 2)
else:
percent_autocons_prod = round(power_autocons * 100, 2)
percent_surplus_prod = round(power_surplus * 100, 2)
cdc_jour = {
'autocons': data_autocons,
'autocons_line': data_autocons_line,
'cons': data_cons,
'cons_line': data_cons_line,
'prod': data_prod,
'prod_line': data_prod_line,
'surplus': data_surplus,
'surplus_line': data_surplus_line,
'label': label_line_cons,
'label_histo': label_histo_cons,
'label_doughnut': ['Autoconso', 'Alloconso'],
'doughnut_cons': [percent_autocons, percent_cons],
'label_doughnut_prod': ['Autoconso', 'Surplus'],
'doughnut_prod': [percent_autocons_prod, percent_surplus_prod]
}
return cdc_jour
# ------------------------------------------------------
# Functions to manage route
# ------------------------------------------------------
def graph_view_conso(self, scale=None, date_start=None, date_end=None, prm_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 = {}
# Get date start and date end depending on type of scale if scale fill
if scale:
date_start, date_end = self.get_last_day(scale)
# Get scale depending on the date start and date end
if date_start and date_end:
scale = self.get_scale(date_start, date_end)
# Get the data to display in chart
chart_data = self.get_cdc(scale, date_start, date_end, prm_id)
# Build the chart depending on data calculated
result_graph = self.chart_data_cons(chart_data)
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
def graph_view_prod(self, scale=None, date_start=None, date_end=None, prm_id=None):
"""
Fonction appelée pour l'affichage des courbes production
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 = {}
# Get date start and date end depending on type of scale if scale fill
if scale:
date_start, date_end = self.get_last_day(scale)
# Get scale depending on the date start and date end
if date_start and date_end:
scale = self.get_scale(date_start, date_end)
# Get the data to display in chart
chart_data = self.get_cdc(scale, date_start, date_end, prm_id)
# Build the chart depending on data calculated
result_graph = self.chart_data_prod(chart_data)
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