Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found
Sélectionner une révision Git
  • 16.0
  • 18.0
  • 18.0-hugo
3 résultats

Cible

Sélectionner le projet cible
  • lefilament/oacc/oacc_portal_overview_cdc
  • arthur-enercoop/oacc_portal_overview_cdc
2 résultats
Sélectionner une révision Git
  • 16.0
  • 16.0-admin-menu-refactoring
2 résultats
Afficher les modifications

Commits on Source 56

......@@ -9,7 +9,8 @@ exclude: |
# Maybe reactivate this when all README files include prettier ignore tags?
^README\.md$|
# Library files can have extraneous formatting (even minimized)
/static/(src/)?lib/|
/static/(src/)?lib/(.*/)?|
/static/src/js/lib/|
# Repos using Sphinx to generate docs don't need prettying
^docs/_templates/.*\.html$|
# Don't bother non-technical authors with formatting issues in docs
......
......@@ -5,12 +5,12 @@ load-plugins=pylint_odoo
score=n
[ODOOLINT]
readme_template_url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst"
manifest_required_authors=Le Filament
manifest_required_keys=license
manifest_deprecated_keys=description,active
license_allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3
valid_odoo_versions=16.0
readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst"
manifest-required-authors=Le Filament
manifest-required-keys=license
manifest-deprecated-keys=description,active
license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3
valid-odoo-versions=16.0
[MESSAGES CONTROL]
disable=all
......
......@@ -3,7 +3,7 @@
"summary": "Gestion portail affichage des courbes de charge",
"author": "Le Filament",
"website": "https://le-filament.com",
"version": "16.0.1.0.1",
"version": "16.0.1.0.2",
"license": "AGPL-3",
"depends": ["web", "oacc_portal"],
"data": [
......
# Copyright 2021- Le Filament (https://le-filament.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import http
import werkzeug
from odoo import _, http
from odoo.exceptions import AccessError
from odoo.http import request
from odoo.addons.oacc_portal.controllers.main import CustomerPortal as CustomerPortal
......@@ -159,6 +162,7 @@ class CustomerPortal(CustomerPortal):
start_date=None,
end_date=None,
data_type=None,
graph_type="histo",
**kw,
):
"""
......@@ -167,10 +171,42 @@ class CustomerPortal(CustomerPortal):
- When click on a consumer, a productor or a PRM
- When click on date range
"""
# TODO: add check that prm_id and partner_id are allowed for this user
operation = request.env["acc.operation"].browse(operation_id)
vals = operation._graph_view_global(
start_date, end_date, partner_id, prm_id, data_type
try:
roles = self._get_role(operation)
except AccessError as e:
raise werkzeug.exceptions.abort(
werkzeug.wrappers.Response(status=401)
) from e
# Si l'opération n'a pas de courbes on renvoie une erreur 401
# Si l'utilisateur n'est pas soit superAdmin, soit Admin, soit Pmo,
# 1. si prm_id est passé il doit aussi y avoir un partner_id
# 2. il faut vérifier qu'il est bien autorisé à accéder au partner_id
# si passé en paramètre
# sinon on renvoie une erreur 401
# (on ne vérifie pas qu'il ait bien accès au prm, aucune donnée ne sera renvoyée
# si les courbes du prm demandées n'appartiennent pas à ce partner)
if not roles.get("isDataCdc") or (
not roles.get("isSuperAdmin")
and not roles.get("isAdmin")
and not roles.get("isPmo")
and (prm_id or partner_id)
and (
(prm_id and not partner_id)
or (
partner_id
and partner_id != request.env.user.commercial_partner_id.id
)
)
):
raise werkzeug.exceptions.abort(werkzeug.wrappers.Response(status=401))
if graph_type == "repartition_data":
vals = operation._get_repartition_data(
start_date, end_date, partner_id, prm_id
)
else:
vals = operation._get_graph(
start_date, end_date, partner_id, prm_id, data_type, graph_type
)
return vals
......@@ -197,8 +233,57 @@ class CustomerPortal(CustomerPortal):
This route is called :
- When click on button export
"""
# TODO: add check that prm_id and partner_id are allowed for this user
operation = request.env["acc.operation"].sudo().browse(int(operation_id))
try:
if (
request.env.user.commercial_partner_id.id
not in operation.partner_role_ids.partner_id.ids
and not request.env.user.has_group("oacc.group_operation_superadmin")
):
raise AccessError(_("You are not allowed to access this operation"))
roles = self._get_role(operation)
except AccessError as e:
raise werkzeug.exceptions.abort(
werkzeug.wrappers.Response(status=401)
) from e
# Si l'opération n'a pas de courbes on renvoie une erreur 401
# Si l'utilisateur n'est pas soit superAdmin, soit Admin, soit Pmo,
# 1. le partner_id est obligatoire
# 2. il faut vérifier qu'il est bien autorisé à accéder au partner_id
# 3. il faut vérifier que le PRM correspond bien à une période de ce partner_id
# sur l'opération
# sinon on renvoie une erreur 401
# (on ne vérifie pas qu'il ait bien accès au prm, aucune donnée ne sera renvoyée
# si les courbes du prm demandées n'appartiennent pas à ce partner)
if not roles.get("isDataCdc") or (
not roles.get("isSuperAdmin")
and not roles.get("isAdmin")
and not roles.get("isPmo")
and (
not partner_id
or (
partner_id
and int(partner_id) != request.env.user.commercial_partner_id.id
)
or (
prm_id
and (
int(prm_id)
not in operation.acc_injection_period_ids.filtered(
lambda p: p.partner_id.id == int(partner_id)
).acc_counter_id.ids
and int(prm_id)
not in operation.acc_delivery_period_ids.filtered(
lambda p: p.partner_id.id == int(partner_id)
).acc_counter_id.ids
)
)
)
):
raise werkzeug.exceptions.abort(werkzeug.wrappers.Response(status=401))
file_values = operation._export_cdc(
start_date, end_date, partner_id, prm_id, data_type
)
......
from . import acc_enedis_cdc
from . import acc_operation
# Copyright 2021- Le Filament (https://le-filament.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import _, api, models
from odoo.exceptions import ValidationError
from odoo.osv import expression
from odoo.addons.api_connector.tools.date_utils import local_to_utc
class AccEnedisCdc(models.Model):
_inherit = "acc.enedis.cdc"
# ------------------------------------------------------
# Actions
# ------------------------------------------------------
# ------------------------------------------------------
# Business methods
# ------------------------------------------------------
@api.model
def _get_step_from_date(self, start_date, end_date):
"""
Fonction retournant le pas des courbes en fonction de 2 dates.
:return:
display_hourly_curves (boolean) : whether or not hourly curves
should be displayed
step: hour/month/year
step_display_curve: hour/day/month/year
"""
display_hourly_curves = False
step = "hour"
step_display_curve = "hour"
# Calculate delta between 2 dates
delta = (end_date - start_date).days
if delta > 1 and delta <= 31:
step_display_curve = "day"
display_hourly_curves = True
elif delta > 31 and delta <= 366:
step = "month"
step_display_curve = "month"
elif delta > 366:
step = "year"
step_display_curve = "year"
return display_hourly_curves, step, step_display_curve
@api.model
def _read_group_process_groupby(self, gb, query):
"""
Overrides models method to avoid getting wrong display format
And manage granluarity = "minute" for 30 minutes curves
"""
initial_gb = gb
if self._context.get("portal_acc_curves") and gb == "date_slot:minute":
gb = "date_slot:hour"
res = super()._read_group_process_groupby(gb, query)
if self._context.get("portal_acc_curves"):
if res["type"] == "datetime":
res["display_format"] = "dd/MM/yyyy HH:mm"
if initial_gb == "date_slot:minute":
res["groupby"] = res["groupby"].replace("hour", "minute")
res["interval"] = relativedelta(minutes=30)
res["granularity"] = res["granularity"].replace("hour", "minute")
res["qualified_field"] = res["qualified_field"].replace(
"hour", "minute"
)
return res
@api.model
def _get_curves(
self,
operation_id,
slot_type,
start_date,
end_date,
prm_id=None,
partner_id=None,
curve_types=None,
extra_curve_type=None,
):
"""
Fonction permettant de récupérer les courbes de charge pour graphique ou export
:param: int operation_id: opération concernée
char slot_type: type de slot pour la query ("minute", "hour", "month" ou
"year")
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
[char] curve_types: type de données
char extra_curve_type : extra curve to be retrieved (optional)
(allowed values : 'cons', 'autocons', 'prod', 'surplus')
@returns: liste de dictionnaires resultat de la requête :
- 1 entrée par date
- 1 champ par type de courbe
"""
start_date_tz = local_to_utc(start_date, "Europe/Paris")
end_date_tz = local_to_utc(end_date, "Europe/Paris")
domain = [
("acc_operation_id", "=", operation_id),
("date_slot", ">=", start_date_tz),
("date_slot", "<", end_date_tz),
]
if partner_id:
partner_domain = [("partner_id", "=", partner_id)]
if prm_id:
partner_domain = expression.AND(
[partner_domain, [("acc_counter_id", "=", prm_id)]]
)
if extra_curve_type and extra_curve_type in (
"cons",
"autocons",
"prod",
"surplus",
):
partner_domain = expression.OR(
[partner_domain, [("comp_data_type", "=", extra_curve_type)]]
)
else:
partner_domain = [("partner_id", "!=", False)]
domain = expression.AND([domain, partner_domain])
if curve_types:
domain = expression.AND([domain, [("comp_data_type", "in", curve_types)]])
res = (
self.env["acc.enedis.cdc"]
.with_context(fill_temporal=True, tz="Europe/Paris", portal_acc_curves=True)
.read_group(
domain,
["date_slot", "power:sum"],
["date_slot:" + slot_type, "comp_data_type"],
lazy=False,
)
)
final_res = []
prev_final_line = {}
for line in res:
if (
prev_final_line
and prev_final_line["date"] == line["date_slot:" + slot_type]
):
prev_final_line.update(
{
line["comp_data_type"]: line["power"] / 2 / 1000,
}
)
else:
new_line = {
"date": line["date_slot:" + slot_type],
line["comp_data_type"]: line["power"] / 2 / 1000,
}
final_res.append(new_line)
prev_final_line = new_line
# Add computed values
for final_line in final_res:
if not curve_types or all(
value in curve_types for value in ["autoprod", "prod", "surplus"]
):
final_line.update(
{"autoprod": final_line["prod"] - final_line["surplus"]}
)
if not curve_types or all(
value in curve_types for value in ["allocons", "cons", "autocons"]
):
final_line.update(
{"allocons": final_line["cons"] - final_line["autocons"]}
)
return final_res
@api.model
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 "minute", "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 ("minute", "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
@api.model
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
"""
@api.model
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
date start_date : first date to be retrieved
date end_date : last date 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', 'prod', 'surplus')
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"))
start_datetime = local_to_utc(start_date, "Europe/Paris")
end_datetime = local_to_utc(end_date, "Europe/Paris")
result = f"""
WHERE cdc.acc_operation_id = {operation_id}
AND cdc.date_slot >= '{start_datetime}'
AND cdc.date_slot < '{end_datetime}'
"""
if partner_id:
result += f" AND ((cdc.partner_id = {int(partner_id)} "
if prm_id:
result += f" AND cdc.acc_counter_id = {int(prm_id)}) "
else:
result = f"{result})"
if extra_curve_type and extra_curve_type in (
"cons",
"autocons",
"prod",
"surplus",
):
result = f"{result} OR cdc.comp_data_type = '{extra_curve_type}' )"
else:
result = f"{result})"
return result
@api.model
def _group_clause(self, date_slot):
"""
Function to build GROUP BY section of query for retrieving curves
@param
char date_slot : granularity
(one of "minute", "hour", "day", "month", "year")
"""
if date_slot not in ("minute", "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')
"""
@api.model
def _order_clause(self):
return "ORDER BY date_slot ASC;"
@api.model
def _cdc_by_query_cons(
self,
operation_id,
slot_type,
start_date,
end_date,
prm_id=None,
partner_id=None,
curve_types=None,
):
"""
Fonction permettant de récupérer les données pour les consommateurs
:param: int operation_id: opération concernée
char slot_type: type de slot pour la query ("minute", "hour", "month" ou
"year")
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
[char] curve_types: type de données
@returns: resultat de la requête
(labels et data pour les charts à afficher)
"""
if curve_types is None:
curve_types = ["cons", "autocons", "prod"]
query = (
self._select_clause(date_slot=slot_type, curve_types=curve_types)
+ self._from_clause()
+ self._where_clause(
operation_id,
start_date,
end_date,
prm_id,
"prod" if "prod" in curve_types else None,
partner_id,
)
+ "AND cdc.comp_data_type IN %s"
+ self._group_clause(date_slot=slot_type)
+ self._order_clause()
)
self.env.cr.execute(query, (tuple(curve_types),))
return self.env.cr.fetchall()
@api.model
def _get_cdc_by_query_cons(
self,
operation_id,
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: int operation_id : Opération concernée
char slot_type: type de slot pour la query ("minute", "hour", "month" ou
"year")
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: resultat de la requête
(labels et data pour les charts à afficher)
"""
label = []
data_autocons = []
data_allocons = []
data_cons = []
data_prod = []
raw_data = self._cdc_by_query_cons(
operation_id, slot_type, start_date, end_date, prm_id, partner_id
)
for row in raw_data:
label.append(row[0])
data_cons.append({"x": row[0], "y": round(row[1], 2)})
data_autocons.append({"x": row[0], "y": round(row[2], 2)})
data_allocons.append({"x": row[0], "y": round(row[1] - row[2], 2)})
data_prod.append({"x": row[0], "y": round(row[3], 2)})
cdc_cons = {
"label": label,
"autocons": data_autocons,
"allocons": data_allocons,
"cons": data_cons,
"prod": data_prod,
}
return cdc_cons
@api.model
def _get_cdc_by_query_daily_histo_cons(
self,
operation_id,
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: int operation_id : Opération concernée
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)
"""
label_histo = []
data_autocons_histo = []
data_allocons_histo = []
query = (
self._select_clause(date_slot="day", curve_types=["autocons", "allocons"])
+ self._from_clause()
+ self._where_clause(
operation_id=operation_id,
start_date=start_date,
end_date=end_date,
prm_id=prm_id,
partner_id=partner_id,
)
+ self._group_clause(date_slot="day")
+ self._order_clause()
)
self.env.cr.execute(query)
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_cons = {
"autocons_histo": data_autocons_histo,
"allocons_histo": data_allocons_histo,
"label_histo": label_histo,
}
return cdc_cons
@api.model
def _cdc_by_query_prod(
self,
operation_id,
slot_type,
start_date,
end_date,
prm_id=None,
partner_id=None,
curve_types=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: int operation_id : Opération concernée
char slot_type: type de slot pour la query ("minute", "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
[char] curve_types: type de données
:return: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
if curve_types is None:
curve_types = ["autoprod", "surplus"]
query = (
self._select_clause(date_slot=slot_type, curve_types=curve_types)
+ self._from_clause()
+ self._where_clause(
operation_id=operation_id,
start_date=start_date,
end_date=end_date,
prm_id=prm_id,
partner_id=partner_id,
)
+ self._group_clause(date_slot=slot_type)
+ self._order_clause()
)
self.env.cr.execute(query)
return self.env.cr.fetchall()
@api.model
def _get_cdc_by_query_prod(
self,
operation_id,
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: int operation_id : Opération concernée
char slot_type: type de slot pour la query ("minute", "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)
"""
label = []
data_autocons = []
data_surplus = []
raw_data = self._cdc_by_query_prod(
operation_id, slot_type, start_date, end_date, prm_id, partner_id
)
for row in raw_data:
label.append(row[0])
data_autocons.append({"x": row[0], "y": round(row[1], 2)})
data_surplus.append({"x": row[0], "y": round(row[2], 2)})
cdc_prod = {
"label": label,
"autocons_prod": data_autocons,
"surplus": data_surplus,
}
return cdc_prod
@api.model
def _get_cdc_by_query_daily_histo_prod(
self, operation_id, 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: int operation_id : Opération concernée
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)
"""
label_histo = []
data_autocons_prod_histo = []
data_surplus_histo = []
query = (
self._select_clause(date_slot="day", curve_types=["autoprod", "surplus"])
+ self._from_clause()
+ self._where_clause(
operation_id=operation_id,
start_date=start_date,
end_date=end_date,
prm_id=prm_id,
partner_id=partner_id,
)
+ self._group_clause(date_slot="day")
+ self._order_clause()
)
self.env.cr.execute(query)
raw_data = self.env.cr.fetchall()
for row in raw_data:
label_histo.append(row[0])
data_autocons_prod_histo.append(round(row[1], 2))
data_surplus_histo.append(round(row[2], 2))
cdc_jour = {
"label_histo": label_histo,
"autocons_prod_histo": data_autocons_prod_histo,
"surplus_histo": data_surplus_histo,
}
return cdc_jour
# ------------------------------------------------------
# Functions to manage route
# ------------------------------------------------------
......@@ -7,7 +7,15 @@ from dateutil.relativedelta import relativedelta
from odoo import fields, http, models
from ..tools import export_cdc
DATA_TYPE_MAP = {
"pmo": ["autocons", "allocons", "autocons_prod", "surplus"],
"cons": ["autocons", "allocons"],
"prod": ["autocons_prod", "surplus"],
}
EXPORT_DATA_TYPE_MAP = {
"cons": ["cons", "autocons", "allocons"],
"prod": ["prod", "autocons_prod", "surplus"],
}
class AccOperation(models.Model):
......@@ -53,13 +61,85 @@ class AccOperation(models.Model):
"target": "new",
}
def _graph_view_global(
@staticmethod
def _get_step_from_date(start_date, end_date):
"""
Fonction retournant le pas des courbes en fonction de 2 dates.
:return:
display_hourly_curves (boolean) : whether or not hourly curves
should be displayed
step: hour/month/year
step_display_curve: hour/day/month/year
"""
display_hourly_curves = False
step = "hour"
step_display_curve = "hour"
# Calculate delta between 2 dates
delta = (end_date - start_date).days
if 1 < delta <= 31:
step_display_curve = "day"
display_hourly_curves = True
elif 31 < delta <= 366:
step = "month"
step_display_curve = "month"
elif delta > 366:
step = "year"
step_display_curve = "year"
return display_hourly_curves, step, step_display_curve
def _get_repartition_data(
self,
start_date,
end_date,
filter_partner_id,
filter_prm_id,
):
from ..tools import prepare_repartition_data
self.ensure_one()
start_date = datetime.strptime(start_date, "%d/%m/%Y")
end_date = datetime.strptime(end_date, "%d/%m/%Y") + relativedelta(days=1)
energy_dict = self.env["acc.enedis.cdc.day"]._get_proratized_energy(
acc_operation_id=self.id,
start_date=start_date,
end_date=end_date,
filter_date=False,
exclude_empty_partner=False,
)
(total_prod, total_surplus) = prepare_repartition_data.get_prod_datas_prorata(
energy_dict["prod"]["partner_ids"], filter_partner_id, filter_prm_id
)
if total_prod == 0:
return "Pas de donnée de production pour cette période"
tPartners = prepare_repartition_data.get_partners_data_prorata(
self.env,
energy_dict["cons"]["partner_ids"],
total_prod,
filter_partner_id,
filter_prm_id,
)
tSurplus = {
"surplus": total_surplus,
"percentage": 100 * total_surplus / total_prod if total_prod else 0,
}
render_values = {"tPartners": tPartners, "tSurplus": tSurplus}
html = self.env["ir.ui.view"]._render_template(
"oacc_portal_overview_cdc.repartition_prod_content", render_values
)
return html
def _get_graph(
self,
start_date=None,
end_date=None,
partner_id=None,
prm_id=None,
data_type=None,
chart_type="histo",
):
"""
Fonction appelée pour l'affichage des courbes globales
......@@ -73,40 +153,54 @@ class AccOperation(models.Model):
- "pmo" : vue globale (cons + prod sans filtrage)
- "cons" : vue mon suivi conso (avec filtrage possible)
- "prod" : vue mon suivi production (avec filtrage possible)
char chart_type: type de visualisation attendue :
- histo (histogramme + camembert agrégé)
- curve (courbe à l'heure)
@returns: dictionnaire pour la construction des graphes
"""
self.ensure_one()
result_graph = {}
Cdc_model = self.env["acc.enedis.cdc"]
start_date = datetime.strptime(start_date, "%d/%m/%Y")
end_date = datetime.strptime(end_date, "%d/%m/%Y") + relativedelta(days=1)
(
display_hourly_curves,
step_curve,
step_display_curve,
) = Cdc_model._get_step_from_date(start_date=start_date, end_date=end_date)
) = self._get_step_from_date(start_date=start_date, end_date=end_date)
chart_data = {}
if data_type == "cons" or data_type == "pmo":
chart_data_cons = Cdc_model._get_cdc_by_query_cons(
self.id, step_curve, start_date, end_date, prm_id, partner_id
)
if display_hourly_curves:
chart_data_histo = Cdc_model._get_cdc_by_query_daily_histo_cons(
self.id, start_date, end_date, prm_id, partner_id
if chart_type == "histo":
if step_display_curve != "hour":
chart_data = self.env["acc.enedis.cdc.day"]._get_chart(
acc_operation_id=self.id,
start_date=start_date,
end_date=end_date,
partner_id=partner_id,
prm_id=prm_id,
groupby_date_slot=step_display_curve,
values_type=DATA_TYPE_MAP[data_type],
)
chart_data_cons.update(chart_data_histo)
chart_data.update(chart_data_cons)
if data_type == "prod" or data_type == "pmo":
chart_data_prod = Cdc_model._get_cdc_by_query_prod(
self.id, step_curve, start_date, end_date, prm_id, partner_id
elif step_display_curve == "hour":
chart_data = self.env["acc.enedis.cdc"]._get_chart(
acc_operation_id=self.id,
start_date=start_date,
end_date=end_date,
partner_id=partner_id,
prm_id=prm_id,
groupby_date_slot=step_display_curve,
values_type=DATA_TYPE_MAP[data_type],
)
if display_hourly_curves:
chart_data_histo = Cdc_model._get_cdc_by_query_daily_histo_prod(
self.id, start_date, end_date, prm_id, partner_id
elif chart_type == "curve" and display_hourly_curves:
chart_data = self.env["acc.enedis.cdc"]._get_chart(
acc_operation_id=self.id,
start_date=start_date,
end_date=end_date,
partner_id=partner_id,
prm_id=prm_id,
groupby_date_slot="hour",
values_type=DATA_TYPE_MAP[data_type],
extra_value_type="prod" if data_type != "prod" else None,
)
chart_data_prod.update(chart_data_histo)
chart_data.update(chart_data_prod)
result_graph["chart_data"] = chart_data
result_graph.update(self.get_date_min_max(partner_id))
......@@ -122,7 +216,7 @@ class AccOperation(models.Model):
def _export_cdc(self, start_date, end_date, partner_id, prm_id, data_type):
"""
Fonction permettant d'exporter les courbes Enedis
:param start_date:
:param end_date:
:param partner_id:
......@@ -130,6 +224,8 @@ class AccOperation(models.Model):
:param data_type:
:return:
"""
from ..tools import export_cdc
start = datetime.strptime(start_date, "%d/%m/%Y")
end = datetime.strptime(end_date, "%d/%m/%Y") + relativedelta(days=1)
......@@ -137,30 +233,21 @@ class AccOperation(models.Model):
self, start_date, end_date, partner_id, prm_id, data_type
)
header = export_cdc.make_header_lines(self, partner_id, prm_id, data_type)
if data_type in ["cons"]:
data_file = export_cdc.make_cons_data(
self.env["acc.enedis.cdc"]._cdc_by_query_cons(
self.id,
"minute",
start,
end,
prm_id,
partner_id,
curve_types=["cons", "autocons", "allocons"],
)
)
if data_type in ["prod"]:
data_file = export_cdc.make_prod_data(
self.env["acc.enedis.cdc"]._cdc_by_query_prod(
self.id,
"minute",
start,
end,
prm_id,
partner_id,
curve_types=["autoprod", "surplus", "prod"],
)
data_dict = self.env["acc.enedis.cdc"]._get_curves(
acc_operation_id=self.id,
start_date=start,
end_date=end,
partner_id=int(partner_id) if partner_id else None,
prm_id=int(prm_id) if prm_id else None,
groupby_date_slot="minute",
values_type=EXPORT_DATA_TYPE_MAP[data_type],
exclude_empty_partner=False,
)
data_file = []
if data_type in ["cons"]:
data_file = export_cdc.make_cons_data(data_dict)
elif data_type in ["prod"]:
data_file = export_cdc.make_prod_data(data_dict)
fout = StringIO()
for h_line in header:
......@@ -204,30 +291,29 @@ class AccOperation(models.Model):
def _get_values_init_graph(self, partner_id=None):
self.ensure_one()
values = {}
Cdc_model = self.env["acc.enedis.cdc"]
last_record = Cdc_model._get_last_cdc_record(self.id, partner_id)
date_day_start, date_day_end = Cdc_model._get_interval("day", last_record)
date_day_start, date_day_end = last_record.get_interval("day")
date_day_start = date_day_start.strftime("%d/%m/%Y")
date_day_end = date_day_end.strftime("%d/%m/%Y")
date_week_start, date_week_end = Cdc_model._get_interval("week", last_record)
date_week_start, date_week_end = last_record.get_interval("week")
date_week_start = date_week_start.strftime("%d/%m/%Y")
date_week_end = date_week_end.strftime("%d/%m/%Y")
date_month_start, date_month_end = Cdc_model._get_interval("month", last_record)
date_month_start, date_month_end = last_record.get_interval("month")
date_month_start = date_month_start.strftime("%d/%m/%Y")
date_month_end = date_month_end.strftime("%d/%m/%Y")
date_year_start, date_year_end = Cdc_model._get_interval("year", last_record)
date_year_start, date_year_end = last_record.get_interval("year")
date_year_start = date_year_start.strftime("%d/%m/%Y")
date_year_end = date_year_end.strftime("%d/%m/%Y")
values = {
return {
"date_day_start": date_day_start,
"date_day_end": date_day_end,
"date_week_start": date_week_start,
......@@ -237,5 +323,3 @@ class AccOperation(models.Model):
"date_year_start": date_year_start,
"date_year_end": date_year_end,
}
return values
.daterange-content {
padding-top: 10px;
max-width: 300px;
}
......@@ -22,3 +21,7 @@ Charts
.line_chart_prod {
margin: auto;
}
.collapse-row {
visibility: collapse;
}
......@@ -7,6 +7,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
var publicWidget = require("web.public.widget");
function delayRepartitionTable(oWidget, type) {
oWidget.timeoutID = null;
oWidget.__onChangePeriod(type);
}
publicWidget.registry.OaccOperationChart = publicWidget.Widget.extend({
selector: ".operation_chart",
events: {
......@@ -15,6 +20,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
"click #previous-period": "_onPreviousPeriod",
"click #next-period": "_onNextPeriod",
"change select[name='endpoint']": "_onChangePrm",
"click TABLE.js-repartition-prod TR.js-partner": "_onPartnerClick",
},
/**
......@@ -45,6 +51,8 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
this.date_range_picker = null;
this.chartData = null;
this.timeoutID = null;
},
/**
......@@ -72,6 +80,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
placeholder: "Sélectionner",
});
$('button[id="next-period"]').prop("disabled", true);
$('button[id="previous-period"]').prop("disabled", true);
return this._super().then(function () {
// Récupération des dates de début et fin
......@@ -91,19 +100,20 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
var selected = self.$el.find("option:selected");
self.partner_id = parseInt(selected.data("partner-id"));
self.render_daterangepicker();
self._updatePrevNextButtons();
self.render_graph();
self.render_graph_cdc();
if (self.data_type === "prod") {
self.render_repartition();
}
});
},
render_graph: function () {
render_graph_cdc: function () {
var self = this;
var ctx_line_conso = self.$(".line_chart_conso");
var ctx_line_prod = self.$(".line_chart_prod");
var ctx_pie_conso = self.$(".pie_chart_conso");
var ctx_pie_prod = self.$(".pie_chart_prod");
var ctx_histo_conso = self.$(".histo_chart_conso");
var ctx_histo_prod = self.$(".histo_chart_prod");
this._rpc({
route: "/chart/update_json",
......@@ -114,10 +124,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "curve",
},
}).then(function (data) {
self.scale = data.scale;
self.chartData = data.chart_data;
self.chartDataLine = data.chart_data;
if (ctx_line_conso.length > 0) {
self.chart_line_conso = new Chart(
......@@ -126,6 +137,38 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
);
}
if (ctx_line_prod.length > 0) {
self.chart_line_prod = new Chart(
ctx_line_prod,
self._getLineChartConfig("prod")
);
}
});
},
render_graph: function () {
var self = this;
var ctx_pie_conso = self.$(".pie_chart_conso");
var ctx_pie_prod = self.$(".pie_chart_prod");
var ctx_histo_conso = self.$(".histo_chart_conso");
var ctx_histo_prod = self.$(".histo_chart_prod");
this._rpc({
route: "/chart/update_json",
params: {
operation_id: self.operation,
start_date: self.first_day,
end_date: self.last_day,
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "histo",
},
}).then(function (data) {
self.scale = data.scale;
self.chartData = data.chart_data;
if (ctx_pie_conso.length > 0) {
self.chart_pie_conso = new Chart(
ctx_pie_conso,
......@@ -140,13 +183,6 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
);
}
if (ctx_line_prod.length > 0) {
self.chart_line_prod = new Chart(
ctx_line_prod,
self._getLineChartConfig("prod")
);
}
if (ctx_pie_prod.length > 0) {
self.chart_pie_prod = new Chart(
ctx_pie_prod,
......@@ -160,6 +196,50 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
self._getBarChartConfig("prod")
);
}
// Selenium
var oContainer = ctx_pie_conso.closest("DIV.chart-container");
oContainer.attr(
"data-total-autocons",
self.chartData.total_autocons
);
oContainer.attr(
"data-total-allocons",
self.chartData.total_allocons
);
oContainer.attr("data-total-cons", self.chartData.total_cons);
oContainer = ctx_pie_prod.closest("DIV.chart-container");
oContainer.attr(
"data-total-autocons-prod",
self.chartData.total_autocons_prod
);
oContainer.attr(
"data-total-surplus",
self.chartData.total_surplus
);
oContainer.attr("data-total-prod", self.chartData.total_prod);
});
},
render_repartition: function () {
var self = this;
// Var ctx_repartition = self.$(".repartition_data");
this._rpc({
route: "/chart/update_json",
params: {
operation_id: self.operation,
start_date: self.first_day,
end_date: self.last_day,
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "repartition_data",
},
}).then(function (data) {
$("#repartition_data").html(data);
});
},
......@@ -183,19 +263,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
function (start, end) {
self.first_day = start.format("DD/MM/YYYY");
self.last_day = end.format("DD/MM/YYYY");
self._rpc({
route: "/chart/update_json",
params: {
operation_id: self.operation,
start_date: self.first_day,
end_date: self.last_day,
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
},
}).then(function (data) {
self._updateDataTemplate(data);
});
self._updateChartData();
self._updateChartDataCdc();
if (self.data_type === "prod") {
self._updateRepartitionData();
}
}
);
},
......@@ -213,15 +285,9 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
var data_surplus = [];
if (typeData === "cons") {
if (this.scale === "day") {
data_autocons = this.chartData.autocons_histo;
data_allocons = this.chartData.allocons_histo;
data_label = this.chartData.label_histo;
} else {
data_autocons = this.chartData.autocons;
data_allocons = this.chartData.allocons;
data_label = this.chartData.label;
}
data = {
labels: data_label,
datasets: [
......@@ -239,16 +305,10 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
},
],
};
} else {
if (this.scale === "day") {
data_autocons = this.chartData.autocons_prod_histo;
data_surplus = this.chartData.surplus_histo;
data_label = this.chartData.label_histo;
} else {
data_autocons = this.chartData.autocons_prod;
data_surplus = this.chartData.surplus;
data_label = this.chartData.label;
}
data = {
labels: data_label,
datasets: [
......@@ -320,7 +380,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
title: function (tooltipItems) {
return moment(tooltipItems[0].xLabel)
.locale("fr-FR")
.format("DD/MM/YYYY HH:ss");
.format("DD/MM/YYYY HH:mm");
},
label: function (context, chart) {
return (
......@@ -346,24 +406,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
_getPieChartData: function (typeData) {
var data = {};
var res = [];
var sum_res1 = 0;
var sum_res2 = 0;
if (typeData === "cons") {
this.chartData.autocons.forEach((item) => {
if ("y" in item) {
sum_res1 += item.y;
} else {
sum_res1 += item;
}
});
this.chartData.allocons.forEach((item) => {
if ("y" in item) {
sum_res2 += item.y;
} else {
sum_res2 += item;
}
});
res = [Math.floor(sum_res1), Math.floor(sum_res2)];
res = [
Math.round(this.chartData.total_autocons),
Math.round(this.chartData.total_allocons),
];
data = {
labels: ["AutoConso", "AlloConso"],
datasets: [
......@@ -383,21 +430,10 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
],
};
} else {
this.chartData.autocons_prod.forEach((item) => {
if ("y" in item) {
sum_res1 += item.y;
} else {
sum_res1 += item;
}
});
this.chartData.surplus.forEach((item) => {
if ("y" in item) {
sum_res2 += item.y;
} else {
sum_res2 += item;
}
});
res = [Math.floor(sum_res1), Math.floor(sum_res2)];
res = [
Math.round(this.chartData.total_autocons_prod),
Math.round(this.chartData.total_surplus),
];
data = {
labels: ["AutoConso", "Surplus"],
datasets: [
......@@ -504,11 +540,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
var data = {};
if (typeData === "cons") {
data = {
labels: this.chartData.label,
labels: this.chartDataLine.label,
datasets: [
{
label: "Conso",
data: this.chartData.cons,
data: this.chartDataLine.cons,
backgroundColor: "rgba(57, 120, 187, 0.2)",
borderColor: "rgba(57, 120, 187, 1)",
borderWidth: 1,
......@@ -517,7 +553,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
},
{
label: "Production solaire",
data: this.chartData.prod,
data: this.chartDataLine.prod,
backgroundColor: "rgba(244, 165, 25, 0)",
borderColor: "rgba(244, 165, 25, 1)",
borderWidth: 2,
......@@ -527,7 +563,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
},
{
label: "AutoConso",
data: this.chartData.autocons,
data: this.chartDataLine.autocons,
backgroundColor: "rgba(91, 154, 81, 0.4)",
borderColor: "rgba(91, 154, 81, 1)",
borderWidth: 2,
......@@ -538,11 +574,11 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
};
} else {
data = {
labels: this.chartData.label,
labels: this.chartDataLine.label,
datasets: [
{
label: "AutoConso",
data: this.chartData.autocons_prod,
data: this.chartDataLine.autocons_prod,
backgroundColor: "rgba(91, 154, 81, 0.4)",
borderColor: "rgba(91, 154, 81, 1)",
borderWidth: 2,
......@@ -552,7 +588,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
},
{
label: "Surplus",
data: this.chartData.surplus,
data: this.chartDataLine.surplus,
backgroundColor: "rgba(225, 80, 96, 0.4)",
borderColor: "rgba(225, 80, 96, 1)",
borderWidth: 2,
......@@ -615,7 +651,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
title: function (tooltipItems) {
return moment(tooltipItems[0].xLabel)
.locale("fr-FR")
.format("DD/MM/YYYY HH:ss");
.format("DD/MM/YYYY HH:mm");
},
label: function (context, chart) {
return (
......@@ -641,8 +677,33 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
// --------------------------------------------------------------------------
// Private
// --------------------------------------------------------------------------
_updateChartData: function (title_name) {
waitChart: function (chart) {
if (typeof chart !== "undefined" && chart !== null) {
chart.data.datasets = [];
chart.data.labels = [];
var ctx = chart.ctx;
var width = chart.width;
var height = chart.height;
chart.clear();
ctx.save();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "35px normal 'Helvetica Nueue'";
ctx.fillStyle = "gray";
ctx.fillText("Chargement des données", width / 2, height / 2);
ctx.restore();
}
},
_updateChartDataCdc: function (title_name) {
var self = this;
self.waitChart(self.chart_line_conso);
self.waitChart(self.chart_line_prod);
this._rpc({
route: "/chart/update_json",
params: {
......@@ -652,6 +713,7 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "curve",
},
}).then(function (data) {
if (title_name) {
......@@ -662,11 +724,54 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
"</h3>";
title_cdc.replaceWith(title_upd);
}
self._updateDataTemplateCdc(data);
});
},
_updateChartData: function (title_name) {
var self = this;
this._rpc({
route: "/chart/update_json",
params: {
operation_id: self.operation,
start_date: self.first_day,
end_date: self.last_day,
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "histo",
},
}).then(function (data) {
if (title_name) {
var title_cdc = $(".title_cdc");
var title_upd =
'<h3 class="title_cdc text-center mt-2">' +
title_name +
"</h3>";
title_cdc.replaceWith(title_upd);
}
self._updateDataTemplate(data);
});
},
_updateRepartitionData: function () {
var self = this;
this._rpc({
route: "/chart/update_json",
params: {
operation_id: self.operation,
start_date: self.first_day,
end_date: self.last_day,
partner_id: self.partner_id,
prm_id: self.prm_id,
data_type: self.data_type,
graph_type: "repartition_data",
},
}).then(function (data) {
$("#repartition_data").html(data);
});
},
_exportChartData: function () {
var self = this;
var url = "/chart/export_cdc?operation_id=" + self.operation;
......@@ -690,27 +795,8 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
return "Total : " + tot + " kWh";
},
_updateDataTemplate: function (data) {
_updatePrevNextButtons: function () {
var self = this;
self.chartData = data.chart_data;
self.scale = data.scale;
self.minDate = data.date_min;
self.maxDate = data.date_max;
self.date_range_picker.data("daterangepicker").minDate = moment(
data.date_min,
"DD/MM/YYYY"
);
self.date_range_picker.data("daterangepicker").maxDate = moment(
data.date_max,
"DD/MM/YYYY"
);
if (data.is_curve_line) {
$(".js_curv_line").removeClass("d-none");
} else {
$(".js_curv_line").addClass("d-none");
}
// Disable buttons if first or last date
if (
moment(self.last_day, "DD/MM/YYYY") >=
......@@ -728,19 +814,47 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
} else {
$('button[id="previous-period"]').prop("disabled", false);
}
},
if (self.chart_line_conso !== null) {
self.chart_line_conso.data = self._getLineChartData("cons");
self.chart_line_conso.options.scales.xAxes[0].time.unit =
self.scale;
self.chart_line_conso.update();
}
_updateDataTemplate: function (data) {
var self = this;
self.chartData = data.chart_data;
self.scale = data.scale;
self.minDate = data.date_min;
self.maxDate = data.date_max;
self.date_range_picker.data("daterangepicker").minDate = moment(
data.date_min,
"DD/MM/YYYY"
);
self.date_range_picker.data("daterangepicker").maxDate = moment(
data.date_max,
"DD/MM/YYYY"
);
self._updatePrevNextButtons();
if (data.is_curve_line) {
$(".js_curv_line").removeClass("d-none");
} else {
$(".js_curv_line").addClass("d-none");
}
if (self.chart_pie_conso !== null) {
self.chart_pie_conso.data = self._getPieChartData("cons");
self.chart_pie_conso.options.title.text =
self._updatePieChartTitle(self.chart_pie_conso.data);
self.chart_pie_conso.update();
// Selenium
var ctx_pie_conso = self.$(".pie_chart_conso");
var oContainer = ctx_pie_conso.closest("DIV.chart-container");
oContainer.attr(
"data-total-autocons",
self.chartData.total_autocons
);
oContainer.attr(
"data-total-allocons",
self.chartData.total_allocons
);
oContainer.attr("data-total-cons", self.chartData.total_cons);
}
if (self.chart_histo_conso !== null) {
self.chart_histo_conso.data = self._getBarChartData("cons");
......@@ -749,18 +863,24 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
self.chart_histo_conso.update();
}
if (self.chart_line_prod !== null) {
self.chart_line_prod.data = self._getLineChartData("prod");
self.chart_line_prod.options.scales.xAxes[0].time.unit =
self.scale;
self.chart_line_prod.update();
}
if (self.chart_pie_prod !== null) {
self.chart_pie_prod.data = self._getPieChartData("prod");
self.chart_pie_prod.options.title.text =
self._updatePieChartTitle(self.chart_pie_prod.data);
self.chart_pie_prod.update();
// Selenium
var ctx_pie_prod = self.$(".pie_chart_prod");
oContainer = ctx_pie_prod.closest("DIV.chart-container");
oContainer.attr(
"data-total-autocons-prod",
self.chartData.total_autocons_prod
);
oContainer.attr(
"data-total-surplus",
self.chartData.total_surplus
);
oContainer.attr("data-total-prod", self.chartData.total_prod);
}
if (self.chart_histo_prod !== null) {
......@@ -771,9 +891,36 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
}
},
_updateDataTemplateCdc: function (data) {
var self = this;
self.chartDataLine = data.chart_data;
if (self.chart_line_conso !== null) {
self.chart_line_conso.data = self._getLineChartData("cons");
self.chart_line_conso.update();
}
if (self.chart_line_prod !== null) {
self.chart_line_prod.data = self._getLineChartData("prod");
self.chart_line_prod.update();
}
},
_onPartnerClick: function (ev) {
ev.stopPropagation();
var that = $(ev.currentTarget);
if (!that.hasClass("js-partner"))
that = that.closest(".js-partner");
var target = that.data("target");
$(target).toggleClass("collapse-row");
},
_onBtnPeriodClick: function (ev) {
var self = this;
var $iframe = $(ev.currentTarget).val();
var objquote = $iframe.replaceAll("'", '"');
const obj = JSON.parse(objquote);
this.first_day = obj.first_day;
this.last_day = obj.last_day;
......@@ -783,7 +930,12 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
this.date_range_picker
.data("daterangepicker")
.setEndDate(this.last_day);
self._updatePrevNextButtons();
this._updateChartData(this.title_name);
this._updateChartDataCdc(this.title_name);
if (self.data_type === "prod") {
self._updateRepartitionData();
}
},
_onBtnExportClick: function () {
......@@ -791,11 +943,17 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
},
_onChangePrm: function (ev) {
var self = this;
var selected = $(ev.currentTarget).find("option:selected");
this.title_name = selected.data("name");
this.partner_id = parseInt(selected.data("partner-id"));
this.prm_id = parseInt(selected.data("prm-id"));
this._updateChartData(this.title_name);
this._updateChartDataCdc(this.title_name);
if (self.data_type === "prod") {
self._updateRepartitionData();
}
},
_onPreviousPeriod: function () {
......@@ -805,9 +963,18 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
this._onChangePeriod("next");
},
_onChangePeriod: function (type) {
this.__onChangePeriodInit(type);
if (this.timeoutID != null) {
clearTimeout(this.timeoutID);
}
this.timeoutID = setTimeout(delayRepartitionTable, 700, this, type);
},
__onChangePeriodInit: function (type) {
var self = this;
const first_day = moment(this.first_day, "DD/MM/YYYY");
const last_day = moment(this.last_day, "DD/MM/YYYY");
const delta_days = last_day - first_day;
let delta_month = 0;
if (
......@@ -863,7 +1030,15 @@ odoo.define("oacc_portal_overview_cdc.operation_chart", function (require) {
this.date_range_picker
.data("daterangepicker")
.setEndDate(this.last_day);
self._updatePrevNextButtons();
},
__onChangePeriod: function (type) {
var self = this;
this._updateChartData(this.title_name);
this._updateChartDataCdc(this.title_name);
if (self.data_type === "prod") {
self._updateRepartitionData();
}
},
});
});
......@@ -8,30 +8,50 @@
<t t-call="oacc_portal.layout_op">
<t t-set="type_data" t-value="'pmo'" />
<div
class="operation_chart mb-5"
class="row body-bg op-home operation_chart"
t-att-data-name="type_data"
t-att-data-id="operation.id"
>
<div class="row text-center">
<t t-call="oacc_portal_overview_cdc.nav_button" />
</div>
<div class="row bg-white pt-3 pb-3 text-center">
<t t-call="oacc_portal_overview_cdc.nav_filters" />
<div class="col-12 mb32">
<div class="mb-5">
<div class="row">
<div class="col-12 col-lg-6 p-3">
<div class="row">
<div class="col-12 text-center">
<h2
class="sticky-top bg-white py-2"
>La Consommation</h2>
<t t-call="oacc_portal_overview_cdc.profil_conso" />
<t t-call="oacc_portal_overview_cdc.bilan_conso" />
<t t-call="oacc_portal_overview_cdc.cdc_conso" />
class="d-block d-lg-none"
>La consommation</h2>
</div>
</div>
<t
t-call="oacc_portal_overview_cdc.profil_conso"
/>
<t
t-call="oacc_portal_overview_cdc.bilan_conso"
/>
<t
t-call="oacc_portal_overview_cdc.cdc_conso"
/>
</div>
<div class="col-12 col-lg-6 p-3">
<h2 class="sticky-top bg-white py-2">La Production</h2>
<t t-call="oacc_portal_overview_cdc.profil_prod" />
<t t-call="oacc_portal_overview_cdc.bilan_prod" />
<div class="row">
<div class="col-12 text-center">
<h2
class="d-block d-lg-none"
>La production</h2>
</div>
</div>
<t
t-call="oacc_portal_overview_cdc.profil_prod"
/>
<t
t-call="oacc_portal_overview_cdc.bilan_prod"
/>
<t t-call="oacc_portal_overview_cdc.cdc_prod" />
</div>
</div>
</div>
</div>
</div>
</t>
......@@ -42,22 +62,30 @@
<t t-call="oacc_portal.layout_op">
<t t-set="type_data" t-value="'cons'" />
<div
class="operation_chart mb-5"
class="row body-bg op-home operation_chart"
t-att-data-name="type_data"
t-att-data-id="operation.id"
>
<t t-call="oacc_portal_overview_cdc.nav_filters" />
<div class="col-12 mb32">
<div class="mb-5">
<div class="row">
<t t-call="oacc_portal_overview_cdc.nav_button" />
</div>
<div class="row mb32 bg-white op-detail">
<div class="col-12 col-lg-6 p-3">
<t t-call="oacc_portal_overview_cdc.profil_conso" />
<t
t-call="oacc_portal_overview_cdc.profil_conso"
/>
</div>
<div class="col-12 col-lg-6 p-3">
<t t-call="oacc_portal_overview_cdc.bilan_conso" />
<t
t-call="oacc_portal_overview_cdc.bilan_conso"
/>
</div>
<div class="col-12 p-3">
<t t-call="oacc_portal_overview_cdc.cdc_conso" />
<t
t-call="oacc_portal_overview_cdc.cdc_conso"
/>
</div>
</div>
</div>
</div>
</div>
......@@ -69,61 +97,99 @@
<t t-call="oacc_portal.layout_op">
<t t-set="type_data" t-value="'prod'" />
<div
class="operation_chart mb-5"
class="row body-bg op-home operation_chart"
t-att-data-name="type_data"
t-att-data-id="operation.id"
>
<t t-call="oacc_portal_overview_cdc.nav_filters" />
<div class="col-12 mb32">
<div class="mb-5">
<div class="row ">
<t t-call="oacc_portal_overview_cdc.nav_button" />
</div>
<div class="row mb32 bg-white op-detail">
<div class="col-12 col-lg-6 p-3">
<t t-call="oacc_portal_overview_cdc.profil_prod" />
<t
t-call="oacc_portal_overview_cdc.profil_prod"
/>
</div>
<div class="col-12 col-lg-6 p-3">
<t t-call="oacc_portal_overview_cdc.bilan_prod" />
<t
t-call="oacc_portal_overview_cdc.bilan_prod"
/>
</div>
<div class="col-12 p-3">
<t t-call="oacc_portal_overview_cdc.cdc_prod" />
</div>
<div class="col-12 p-3">
<t
t-call="oacc_portal_overview_cdc.repartition_prod"
/>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="nav_button">
<div class="col-12 mb-3 bg-white">
<template id="nav_filters">
<div
class="col-12 sticky-top2 pt-0 pt-md-2 pt-lg-0 pb-2 bg-light"
style="border-bottom: 1px solid rgb(244, 230, 236);"
>
<div class="d-block d-md-none">
<t t-call="oacc_portal.nav_menu_sm" />
</div>
<t t-if="type_data == 'pmo'">
<div class="mb-2" />
</t>
<t t-else="">
<div class="row">
<div class="col-12">
<div class="title_cdc text-center">
<t t-if="type_data == 'cons' and len(partners) > 1">
<h3 class="title_cdc mt-2">Consommation globale</h3>
<t
t-if="type_data == 'cons' and len(partners) > 1"
>
<h3
class="title_cdc mt-2"
>Consommation globale</h3>
</t>
<t t-elif="type_data == 'prod' and len(partners) > 1">
<h3 class="title_cdc mt-2">Production globale</h3>
<t
t-elif="type_data == 'prod' and len(partners) > 1"
>
<h3
class="title_cdc mt-2"
>Production globale</h3>
</t>
<t
t-elif="type_data in ('cons', 'prod') and len(partners) == 1"
>
<h3 class="title_cdc mt-2">
<h3 class="title_cdc mt-0 mt-md-2">
<t t-out="partners[0].sudo().name" />
</h3>
</t>
</div>
</div>
<div class="col-12">
</div>
</t>
<!-- filters -->
<div class="row">
<div class="col-12 col-xl-6 mb-2 mb-xl-0">
<div class="row">
<div class="col-2 col-xl-1 align-self-center">
<div
class="col-3 col-xl-2 align-self-xl-center text-left"
>
Période
</div>
<div class="col-10 col-xl-5">
<!-- Buttons period -->
<div class="col-9 col-xl-10 align-self-xl-center">
<div
class="btn-period-group d-flex justify-content-evenly flex-wrap"
>
<!-- Buttons period -->
<button
t-att-value="{'first_day': data_values['date_day_start'] or '', 'last_day': data_values['date_day_end' or '']}"
name="day"
class="btn btn-primary btn-period"
class="btn btn-primary btn-period me-1 mb-1"
title="Dernier jour"
aria-label="Dernier jour"
data-mode="day"
......@@ -133,7 +199,7 @@
<button
t-att-value="{'first_day': data_values['date_week_start'] or '', 'last_day': data_values['date_week_end'] or ''}"
name="week"
class="btn btn-primary btn-period btn-week"
class="btn btn-primary btn-period btn-week me-1 mb-1"
title="7 derniers jours"
aria-label="7 derniers jours"
data-mode="week"
......@@ -143,7 +209,7 @@
<button
t-att-value="{'first_day': data_values['date_month_start'] or '', 'last_day': data_values['date_month_end'] or ''}"
name="month"
class="btn btn-primary btn-period"
class="btn btn-primary btn-period me-1 mb-1"
title="Dernier mois"
aria-label="Dernier mois"
data-mode="month"
......@@ -153,7 +219,7 @@
<button
t-att-value="{'first_day': data_values['date_year_start'] or '', 'last_day': data_values['date_year_end'] or ''}"
name="year"
class="btn btn-primary btn-period"
class="btn btn-primary btn-period me-1 mb-1"
title="12 derniers mois"
aria-label="12 derniers mois"
data-mode="year"
......@@ -163,46 +229,56 @@
<button
t-att-value="{'first_day': data_values['date_min'] or '', 'last_day': data_values['date_max'] or ''}"
name="all"
class="btn btn-primary btn-period"
class="btn btn-primary btn-period me-1 mb-1"
title="Tout"
aria-label="Tout"
data-mode="month"
>
Tout
</button>
</div>
<!-- Daterange picker -->
<div class="text-center">
<div class="input-group daterange-content mx-auto">
<button id="previous-period" class="btn btn-light">
<i class="fa fa-angle-double-left" />
<div class="input-group daterange-content">
<button
id="previous-period"
class="btn btn-light"
>
<i
class="fa fa-angle-double-left"
/>
</button>
<input
type="text"
name="daterange"
class="form-control text-center"
/>
<button id="next-period" class="btn btn-light">
<i class="fa fa-angle-double-right" />
<button
id="next-period"
class="btn btn-light"
>
<i
class="fa fa-angle-double-right"
/>
</button>
</div>
</div>
</div>
<div
class="col-2 col-xl-1 align-self-center mt-4 mt-lg-0"
t-if="partners"
>
PRM ou contact
</div>
</div>
<div class="col-12 col-xl-6" t-if="partners">
<div class="row">
<div
class="col-10 col-xl-5 align-self-center mt-4 mt-lg-0"
t-if="partners"
class="col-3 col-xl-2 align-self-xl-center text-left"
>
<span
class="text-center"
>Participant ou compteur</span>
</div>
<div class="col-9 col-xl-10 align-self-xl-center">
<div
class="prm-selection align-items-between justify-content-around d-flex"
class="prm-selection align-items-between justify-content-evenly d-flex"
>
<select
class="form-select"
class="form-select me-2"
aria-label="prm-selection"
name="endpoint"
>
......@@ -254,18 +330,35 @@
href="#"
title="Export"
target="_blank"
class="btn btn-primary"
class="btn btn-primary text-nowrap"
id="export-data"
>
<i class="fa fa-cloud-download " />
<span class="d-none d-md-inline">Exporter</span>
<span
class="d-none d-md-inline"
>Exporter</span>
</a>
</div>
</div>
</div>
<hr />
</div>
</div>
<t t-if="type_data == 'pmo'">
<div class="row">
<div class="col-6 text-center">
<h2
class="pt-1 d-none d-lg-block"
>La consommation</h2>
</div>
<div class="col-6 text-center">
<h2
class="pt-1 d-none d-lg-block"
>La production</h2>
</div>
</div>
</t>
</div>
</template>
<template id="profil_conso">
......@@ -353,4 +446,80 @@
</div>
</template>
<template id="repartition_prod_content">
<div class="table-responsive mt-4">
<table
class="table table-sm js-repartition-prod w-auto mx-auto overflow-hidden"
>
<tbody>
<tr class="fw-bolder bg-light">
<td class="text-uppercase">Surplus</td>
<td class="text-end text-nowrap"><t
t-esc="('%.2f' % tSurplus['surplus'])"
/> kWh</td>
<td class="text-end text-nowrap"><t
t-esc="('%.1f' % tSurplus['percentage']).replace('.', ',')"
/> %</td>
</tr>
<t t-foreach="tPartners.keys()" t-as="tPartner_id">
<t t-set="tPartner" t-value="tPartners[tPartner_id]" />
<tr
class="fw-bolder bg-light js-partner"
t-attf-data-target=".partner_{{tPartner_id}}"
style="cursor: pointer;"
>
<td><t t-esc="tPartner['name']" /></td>
<td class="text-end text-nowrap"><t
t-esc="('%.2f' % tPartner['autocons'])"
/> kWh</td>
<td class="text-end text-nowrap"><t
t-esc="('%.1f' % tPartner['percentage']).replace('.', ',')"
/> %</td>
</tr>
<t t-set="tCounters" t-value="tPartner['counters']" />
<t t-foreach="tCounters.keys()" t-as="tCounter_id">
<t t-set="tCounter" t-value="tCounters[tCounter_id]" />
<tr t-attf-class="collapse-row partner_{{tPartner_id}}">
<td class="ps-3">
<t
t-esc="(tCounter['street']) if tCounter['street'] else ''"
/>
<t
t-esc="(' - ' + tCounter['street2']) if tCounter['street2'] else ''"
/>
<t
t-esc="(' - ' + tCounter['zip'] + ' ' + tCounter['city']) if tCounter['zip'] or tCounter['city'] else ''"
/>
<t
t-esc="(' - ' + tCounter['name']) if tCounter['name'] else ''"
/>
</td>
<td class="text-end text-nowrap"><t
t-esc="('%.2f' % tCounter['autocons'])"
/> kWh</td>
<td class="text-end text-nowrap"><t
t-esc="('%.1f' % tCounter['percentage']).replace('.', ',')"
/> %</td>
</tr>
</t>
</t>
</tbody>
</table>
</div>
<div class="text-center text-muted mt-1 mb-1">
Cliquez sur les éléments pour obtenir les informations détaillées sur les points de soutirage.
</div>
</template>
<template id="repartition_prod">
<div class="ojs_curv_line otext-center p-3 shadow oop-graph">
<h3 class="text-center">Répartition de la production</h3>
<hr class="my-2" />
<div id="repartition_data">
</div>
</div>
</template>
</odoo>
......@@ -4,11 +4,11 @@
<odoo>
<!-- Layout operation -->
<template id="layout_op" inherit_id="oacc_portal.layout_op">
<template id="nav_menu_content" inherit_id="oacc_portal.nav_menu_content">
<xpath expr="//li[@id='menu-accueil']" position="after">
<li
class="nav-item"
t-if="isPmo or isConsumer or isProductor or isAdmin or isSuperAdmin"
t-if="(isPmo or isConsumer or isProductor or isAdmin or isSuperAdmin) and isDataCdc"
>
<a
t-attf-href="/operation/#{slug(operation)}/pmo"
......@@ -19,7 +19,7 @@
</li>
<li
class="nav-item"
t-if="isPmo or isConsumer or isAdmin or isSuperAdmin"
t-if="(isPmo or isConsumer or isAdmin or isSuperAdmin) and isDataCdc"
>
<a
t-attf-href="/operation/#{slug(operation)}/consumer"
......@@ -30,7 +30,7 @@
</li>
<li
class="nav-item"
t-if="isPmo or isProductor or isAdmin or isSuperAdmin"
t-if="(isPmo or isProductor or isAdmin or isSuperAdmin) and isDataCdc"
>
<a
t-attf-href="/operation/#{slug(operation)}/productor"
......
......@@ -3,14 +3,12 @@ import unicodedata
PROD_HEADER = [
"Horodatage",
"Production (W)",
"Production (kWh)",
"Surplus (kWh)",
"Production autoconsommée (kWh)",
]
CONS_HEADER = [
"Horodatage",
"Consommation (W)",
"Consommation (kWh)",
"Alloconsommation (kWh)",
"Autoconsommation (kWh)",
......@@ -55,14 +53,15 @@ def make_filename(
operation, start_date, end_date, partner_id, prm_id, data_type, file_type="csv"
):
"""
Genere le nom du fichier exporte sous la forme
Elocoop_[nom opé]_[date_debut]_[date_fin]_[production ou consommation]_[contact ou PRM].csv
Génère le nom du fichier exporté sous la forme
Elocoop_[nom opé]_[date_debut]_[date_fin]_[production ou consommation]\
_[contact ou PRM].csv
:param operation: id de l operation
:param start_date: date de debut
:param start_date: date de début
:param end_date: date de fin
:param partner_id: id du partner
:param prm_id: id du prm
:param data_type: type de données (consomation ou production)
:param data_type: type de données (consommation ou production)
:param file_type: type de fichier par defaut csv
:return:
"""
......@@ -81,11 +80,11 @@ def make_filename(
return filename
def make_cons_data(raw_data):
def make_cons_data(energy_dict):
"""
make data file with cons hearder
horodatage cons w cons kwh allocons autocans
:param raw_data:
:param energy_dict:
:return:
"""
......@@ -93,79 +92,95 @@ def make_cons_data(raw_data):
data_file_lines = []
rounding = 3
for row in raw_data:
for period in energy_dict:
data_file_lines.append(
";".join(
[
# horodatage
row[0].strftime("%d/%m/%Y %H:%M"),
# consommation en watt
str(round(row[1] * 2000, rounding)),
period.strftime("%d/%m/%Y %H:%M"),
# consommation en kwh
str(round(row[1], rounding)),
str(round(energy_dict[period].get("cons", 0.0), rounding)),
# allocons
str(round(row[3], rounding)),
str(
round(
energy_dict[period].get("cons", 0.0)
- energy_dict[period].get("autocons", 0.0),
rounding,
)
),
# autocons
str(round(row[2], rounding)),
str(round(energy_dict[period].get("autocons", 0.0), rounding)),
]
)
)
sum_value["cons"] += round(row[1], rounding)
sum_value["allo_cons"] += round(row[3], rounding)
sum_value["auto_cons"] += round(row[2], rounding)
sum_value["cons"] += round(energy_dict[period].get("cons", 0.0), rounding)
sum_value["auto_cons"] += round(
energy_dict[period].get("autocons", 0.0), rounding
)
sum_value["allo_cons"] += round(
energy_dict[period].get("cons", 0.0)
- energy_dict[period].get("autocons", 0.0),
rounding,
)
tot = ";".join(
[
"TOTAL",
"",
str(round(sum_value.get("cons"), rounding)),
str(round(sum_value.get("allo_cons"), rounding)),
str(round(sum_value.get("auto_cons"), rounding)),
str(round(sum_value.get("cons", 0.0), rounding)),
str(round(sum_value.get("allo_cons", 0.0), rounding)),
str(round(sum_value.get("auto_cons", 0.0), rounding)),
]
)
data_file_lines.insert(0, tot)
return data_file_lines
def make_prod_data(raw_data):
def make_prod_data(energy_dict):
"""
make data file with prod hearder
horodatage prod w prod kwh surplus autocons
:param raw_data:
:param energy_dict:
:return:
"""
data_file_lines = []
rounding = 3
sum_value = {"prod": 0, "surplus": 0, "auto_cons": 0}
for row in raw_data:
for period in energy_dict:
data_file_lines.append(
";".join(
[
# horodatage
row[0].strftime("%d/%m/%Y %H:%M"),
# production en watt
str(round(row[3] * 2000, rounding)),
period.strftime("%d/%m/%Y %H:%M"),
# production en kwh
str(round(row[3], rounding)),
str(round(energy_dict[period].get("prod", 0.0), rounding)),
# surplus
str(round(row[2], rounding)),
str(round(energy_dict[period].get("surplus", 0.0), rounding)),
# autocons
str(round(row[1], rounding)),
str(
round(
energy_dict[period].get("prod", 0.0)
- energy_dict[period].get("surplus", 0.0),
rounding,
)
),
]
)
)
sum_value["prod"] += round(row[3], rounding)
sum_value["surplus"] += round(row[2], rounding)
sum_value["auto_cons"] += round(row[1], rounding)
sum_value["prod"] += round(energy_dict[period].get("prod", 0.0), rounding)
sum_value["surplus"] += round(energy_dict[period].get("surplus", 0.0), rounding)
sum_value["auto_cons"] += round(
energy_dict[period].get("prod", 0.0)
- energy_dict[period].get("surplus", 0.0),
rounding,
)
tot = ";".join(
[
"TOTAL",
"",
str(round(sum_value.get("prod"), rounding)),
str(round(sum_value.get("surplus"), rounding)),
str(round(sum_value.get("auto_cons"), rounding)),
str(round(sum_value.get("prod", 0.0), rounding)),
str(round(sum_value.get("surplus", 0.0), rounding)),
str(round(sum_value.get("auto_cons", 0.0), rounding)),
]
)
data_file_lines.insert(0, tot)
......
def get_prod_datas_prorata(
inj_partners_node, filter_partner_id=None, filter_counter_id=None
):
total_surplus = 0
total_prod = 0
for partner_id in inj_partners_node: # producteur
if filter_partner_id is not None and partner_id != filter_partner_id:
continue
inj_counters_node = inj_partners_node[partner_id]["acc_counter_ids"]
for counter_id in inj_counters_node: # injection
if filter_counter_id is not None and counter_id != filter_counter_id:
continue
total_surplus = total_surplus + inj_counters_node[counter_id].get(
"surplus", 0.0
)
total_prod = total_prod + inj_counters_node[counter_id].get("prod", 0.0)
return total_prod, total_surplus
def _sort_partners_prorata(
del_partners_node, filter_partner_id=None, filter_counter_id=None
):
tPartners = {}
for partner_id in del_partners_node: # consommateur
del_counters_node = del_partners_node[partner_id]["acc_counter_ids"]
autocons = 0
for counter_id in del_counters_node: # soutirage
if filter_counter_id is not None:
autocons += del_counters_node[counter_id][
"autocons_per_inj_counter"
].get(filter_counter_id, 0.0)
elif filter_partner_id is not None:
autocons += del_counters_node[counter_id][
"autocons_per_inj_partner"
].get(filter_partner_id, 0.0)
else:
autocons += del_counters_node[counter_id].get("autocons")
tPartners[partner_id] = autocons
sorted_partner = dict(
sorted(tPartners.items(), key=lambda item: item[1], reverse=True)
)
return sorted_partner
def _sort_counters_prorata(
del_counters_node, filter_partner_id=None, filter_counter_id=None
):
tCounters = {}
for counter_id in del_counters_node: # soutirage
autocons = 0
if filter_counter_id:
autocons = (
del_counters_node[counter_id]
.get("autocons_per_inj_counter", {})
.get(filter_counter_id, 0.0)
)
elif filter_partner_id:
autocons = (
del_counters_node[counter_id]
.get("autocons_per_inj_partner", {})
.get(filter_partner_id, 0.0)
)
else:
autocons = del_counters_node[counter_id].get("autocons", 0.0)
tCounters[counter_id] = autocons
sorted_counter = dict(
sorted(tCounters.items(), key=lambda item: item[1], reverse=True)
)
return sorted_counter
def _get_counters_data_prorata(
del_counters_dict,
del_counters_ndoe,
total,
filter_partner_id=None,
filter_counter_id=None,
):
tCounters = {}
subtotal = 0
sorted_counter = _sort_counters_prorata(
del_counters_ndoe, filter_partner_id, filter_counter_id
)
for counter_id in sorted_counter: # soutirage
tCounter = {
"name": del_counters_dict[counter_id]["name"],
"street": del_counters_dict[counter_id]["street"],
"street2": del_counters_dict[counter_id]["street2"],
"zip": del_counters_dict[counter_id]["zip"],
"city": del_counters_dict[counter_id]["city"],
"autocons": sorted_counter[counter_id],
"percentage": 100 * sorted_counter[counter_id] / total,
}
subtotal = subtotal + sorted_counter[counter_id]
tCounters[counter_id] = tCounter
return subtotal, tCounters
def get_partners_data_prorata(
env,
del_partners_node,
total,
filter_partner_id=None,
filter_counter_id=None,
):
tPartners = {}
dbPartners = env["res.partner"].browse(del_partners_node.keys())
del_partners_dict = {
partner["id"]: partner["name"] for partner in dbPartners.read(["name"])
}
del_counter_ids = {}
for partner_id in dbPartners.ids:
acc_counter_ids = del_partners_node[partner_id].get("acc_counter_ids", [])
for counter_id in acc_counter_ids:
del_counter_ids[counter_id] = acc_counter_ids[counter_id]
if 0 in del_partners_node:
del_partners_dict[0] = "Pas de participant lié".upper()
acc_counter_ids = del_partners_node[0].get("acc_counter_ids", [])
for counter_id in acc_counter_ids:
del_counter_ids[counter_id] = acc_counter_ids[counter_id]
dbCounters = env["acc.counter"].browse(del_counter_ids.keys())
del_counters_dict = {
counter["id"]: {
"name": counter["name"],
"street": counter["street"],
"street2": counter["street2"],
"zip": counter["zip"],
"city": counter["city"],
}
for counter in dbCounters.read(["name", "street", "street2", "zip", "city"])
}
sorted_partner = _sort_partners_prorata(
del_partners_node, filter_partner_id, filter_counter_id
)
for partner_id in sorted_partner: # consommateur
tPartner = {}
tPartner["name"] = del_partners_dict[partner_id]
del_counters_node = del_partners_node[partner_id]["acc_counter_ids"]
(subtotal, tCounters) = _get_counters_data_prorata(
del_counters_dict,
del_counters_node,
total,
filter_partner_id,
filter_counter_id,
)
tPartner["autocons"] = subtotal
tPartner["percentage"] = 100 * subtotal / total
tPartner["counters"] = tCounters
tPartners[partner_id] = tPartner
return tPartners