Newer
Older
# Copyright 2023 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.exceptions import ValidationError
from odoo.tools import date_utils
DEFAULT_MONTH_RANGE = 3
class AccOperation(models.Model):
_inherit = "acc.operation"
# ------------------------------------------------------
# Actions
# ------------------------------------------------------
def action_view_courbes(self):
"""
"type": "ir.actions.act_url",
"url": "/operation/%s" % (self.id),
"target": "new",
# ------------------------------------------------------
# Business methods
# ------------------------------------------------------
def get_power_tot(self):
"""
Fonction retournant la consommation totale, l'autoconsommation totale
et la production totale du dernier mois.
:return: la somme de la conso totale de tous les consommateurs,
la somme de l autoconso totale de tous les consommateurs,
la sommme de la prod totale de tous les producteurs
la date de début de mois
"""
last_record = self.get_the_last_day()
date_start, date_end = self.get_last_day("month", last_record)
query = """
SELECT
date_trunc('month', A.date_slot) AS date_slot,
(SUM( (CASE
WHEN comp_data_type = 'cons' THEN A.power
ELSE 0 END) )/2) / 1000 as conso_tot,
(SUM( (CASE
WHEN comp_data_type = 'prod'
THEN A.power ELSE 0 END) )/2) / 1000 as prod_tot,
(SUM( (CASE WHEN
comp_data_type = 'autocons' THEN A.power
ELSE 0 END) )/2) / 1000 as autoconso_tot
FROM
acc_enedis_cdc A
JOIN
acc_operation E ON E.id = A.acc_operation_id
WHERE
A.acc_operation_id IS NOT NULL
AND A.acc_operation_id = %s
AND A.date_slot >= %s
GROUP BY date_trunc('month', A.date_slot);
"""
query_params = (
self.id,
date_start,
date_end,
)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.fetchall()
return raw_data[0][1], raw_data[0][2], raw_data[0][3], date_start
def get_the_last_day(self):
"""
Fonction retournant la date du dernier enregistrement
"""
# Get last date slot recorded
last_record = (
self.env["acc.enedis.cdc"]
.sudo()
.search(
[
("acc_operation_id", "in", self.ids),
],
limit=1,
order="date_slot DESC",
)
)
if not last_record:
raise ValidationError(_("L'opération ne possède pas de données"))
return last_record
def get_last_day(self, scale, last_record):
"""
Fonction retournant une date de début et une date de fin.
Ces dates sont calculées en fonction de l'échelle choisie et du dernier
élément enregistré
- day: la date de début est égale à la dernière date
avec un 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
"""
# Convert end datetime to timezone
last_day_start = last_record.date_slot.replace(hour=0, minute=0, second=0)
last_day_end = last_day_start + relativedelta(days=1)
# Get end time slot for previous month with timezone
# Manage if date is the last day of the month
if fields.Date.to_date(last_day_start) == fields.Date.to_date(
date_utils.end_of(last_record.date_slot, "month")
):
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
end_month = last_day_end.replace(day=1)
else:
end_month = last_day_start.replace(day=1)
if scale == "semestre":
date_end = end_month
date_start = end_month - relativedelta(months=6)
elif scale == "year":
date_end = end_month
date_start = end_month.replace(month=1, day=1)
elif scale == "week":
date_start = last_day_end - relativedelta(days=7)
date_end = last_day_end
elif scale == "day":
date_start = last_day_start
date_end = last_day_end
# month by default
else:
date_start = end_month - relativedelta(months=1)
date_end = end_month
return date_start, date_end
def get_step_from_date(self, date_start, date_end, scale=None):
"""
Fonction retournant le pas des courbes en fonction de 2 dates.
:return: step: hour/day/month/year
"""
# Calculate delta between 2 dates
delta = (date_end - date_start).days
if delta <= 1:
step_display_courbe = "hour"
step = "hour"
elif delta < 32:
step_display_courbe = "day"
step = "hour"
scale = "week"
elif delta > 365:
step = "year"
step_display_courbe = "year"
else:
step = "month"
step_display_courbe = "month"
return scale, step, step_display_courbe
def get_cdc_by_query_cons(self, slot_type, date_start, date_end, prm_ids=None):
"""
Fonction permettant de récupérer les données pour la
construction des chart pour une ou des opérations données
pour les consommateurs
:param slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
date_start: date début
date_end: date de fin
@returns: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
label = []
data_autocons = []
data_allocons = []
data_cons = []
data_prod = []
data_surplus = []
query = """
SELECT
date_trunc(%s, A.date_slot) AS date_slot,
(SUM( (CASE WHEN
comp_data_type = 'autocons' THEN A.power
ELSE 0 END) )/2) / 1000 as autocons,
(SUM( (CASE
WHEN comp_data_type = 'prod'
THEN A.power ELSE 0 END) )/2) / 1000 as prod,
((SUM( (CASE WHEN comp_data_type = 'cons' THEN A.power ELSE 0 END)) -
SUM(CASE WHEN comp_data_type = 'autocons' THEN A.power ELSE 0 END) ) / 2) / 1000 as allocons,
(SUM( (CASE
WHEN comp_data_type = 'cons' THEN A.power
ELSE 0 END) )/2) / 1000 as cons
FROM
acc_enedis_cdc A
JOIN
acc_operation E ON E.id = A.acc_operation_id
WHERE
A.acc_operation_id IS NOT NULL
AND A.acc_operation_id IN %s
AND ( A.acc_counter_id IN %s OR A.comp_data_type = 'prod' )
AND A.date_slot >= %s
GROUP BY date_trunc(%s, A.date_slot)
ORDER BY date_slot ASC;
"""
query_params = (
slot_type,
tuple(self.ids),
tuple(prm_ids.ids),
date_start,
date_end,
slot_type,
)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.fetchall()
for row in raw_data:
data_autocons.append({"x": row[0], "y": round(row[1], 2)})
data_prod.append({"x": row[0], "y": round(row[2], 2)})
data_allocons.append({"x": row[0], "y": round(row[3], 2)})
data_cons.append({"x": row[0], "y": round(row[4], 2)})
label.append(row[0])
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
cdc_jour = {
"autocons": data_autocons,
"prod": data_prod,
"allocons": data_allocons,
"label": label,
"cons": data_cons,
"surplus": data_surplus,
}
return cdc_jour
def get_cdc_by_query_histo_cons(
self, slot_type, date_start, date_end, prm_ids=None
):
"""
Fonction permettant de récupérer les données pour la construction
des chart pour une ou des opérations données pour les consommateurs
:param slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
date_start: date début
date_end: date de fin
:return: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
label_histo = []
data_autocons_histo = []
data_allocons_histo = []
query = """
SELECT
date_trunc(%s, A.date_slot) AS date_slot,
(SUM( (CASE
WHEN comp_data_type = 'autocons'
THEN A.power ELSE 0 END) )/2) / 1000 as autocons,
((SUM( (CASE WHEN comp_data_type = 'cons' THEN A.power ELSE 0 END)) -
SUM(CASE WHEN comp_data_type = 'autocons' THEN A.power ELSE 0 END) ) / 2) / 1000 as allocons
FROM acc_enedis_cdc A
JOIN acc_operation E ON E.id = A.acc_operation_id
WHERE A.acc_operation_id IS NOT NULL
AND A.acc_operation_id IN %s
AND A.acc_counter_id IN %s
AND A.date_slot >= %s
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
GROUP BY date_trunc(%s, A.date_slot)
ORDER BY date_slot ASC;
"""
query_params = (
slot_type,
tuple(self.ids),
tuple(prm_ids.ids),
date_start,
date_end,
slot_type,
)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.fetchall()
for row in raw_data:
data_autocons_histo.append(round(row[1], 2))
data_allocons_histo.append(round(row[2], 2))
label_histo.append(row[0])
cdc_jour = {
"autocons_histo": data_autocons_histo,
"allocons_histo": data_allocons_histo,
"label_histo": label_histo,
}
return cdc_jour
def get_cdc_by_query_prod(self, slot_type, date_start, date_end, prm_ids=None):
"""
Fonction permettant de récupérer les données pour la construction des chart
pour une ou des opérations données pour les consommateurs
:param slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
date_start: date début
date_end: date de fin
:return: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
label = []
data_autocons = []
data_surplus = []
label_histo = []
data_autocons_histo = []
data_surplus_histo = []
query = """
SELECT
date_trunc(%s, A.date_slot) AS date_slot,
((SUM((CASE
WHEN comp_data_type = 'prod' THEN A.power
ELSE 0 END))
- SUM(CASE
WHEN comp_data_type = 'surplus' THEN A.power
ELSE 0 END)) / 2) / 1000 as autocons,
(SUM( (CASE
WHEN comp_data_type = 'surplus' THEN A.power
ELSE 0 END) )/2) / 1000 as surplus
FROM acc_enedis_cdc A
JOIN acc_operation E ON E.id = A.acc_operation_id
WHERE A.acc_operation_id IS NOT NULL
AND A.acc_counter_id IN %s
AND A.acc_operation_id IN %s
AND A.date_slot >= %s
GROUP BY date_trunc(%s, A.date_slot)
ORDER BY date_slot ASC;
"""
query_params = (
slot_type,
tuple(prm_ids.ids),
tuple(self.ids),
date_start,
date_end,
slot_type,
)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.fetchall()
for row in raw_data:
if slot_type == "day":
data_autocons_histo.append(round(row[1], 2))
data_surplus_histo.append(round(row[2], 2))
label_histo.append(row[0])
data_autocons.append({"x": row[0], "y": round(row[1], 2)})
data_surplus.append({"x": row[0], "y": round(row[2], 2)})
label.append(row[0])
cdc_jour = {
"autocons_prod": data_autocons,
"label": label,
"surplus": data_surplus,
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
"label_histo": label_histo,
"surplus_histo": data_surplus_histo,
}
return cdc_jour
def get_cdc_by_query_histo_prod(
self, slot_type, date_start, date_end, prm_ids=None
):
"""
Fonction permettant de récupérer les données pour la construction des chart
pour une ou des opérations données pour les consommateurs
:param slot_type: type de slot pour la query ('month' ou 'hour' ou 'year')
date_start: date début
date_end: date de fin
:return: un dictionnaire de données
(labels et data pour les charts à afficher)
"""
label_histo = []
data_autocons_prod_histo = []
data_surplus_histo = []
query = """
SELECT
date_trunc(%s, A.date_slot) AS date_slot,
((SUM((CASE
WHEN comp_data_type = 'prod' THEN A.power
ELSE 0 END))
- SUM(CASE
WHEN comp_data_type = 'surplus' THEN A.power
ELSE 0 END)) / 2) / 1000 as autocons,
(SUM( (CASE
WHEN comp_data_type = 'surplus' THEN A.power
ELSE 0 END) )/2) / 1000 as surplus
FROM acc_enedis_cdc A
JOIN acc_operation E ON E.id = A.acc_operation_id
WHERE A.acc_operation_id IS NOT NULL
AND A.acc_counter_id IN %s
AND A.acc_operation_id IN %s
AND A.date_slot >= %s
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
GROUP BY date_trunc(%s, A.date_slot)
ORDER BY date_slot ASC;
"""
query_params = (
slot_type,
tuple(prm_ids.ids),
tuple(self.ids),
date_start,
date_end,
slot_type,
)
self.env.cr.execute(query, query_params)
raw_data = self.env.cr.fetchall()
for row in raw_data:
data_autocons_prod_histo.append(round(row[1], 2))
data_surplus_histo.append(round(row[2], 2))
label_histo.append(row[0])
cdc_jour = {
"autocons_prod_histo": data_autocons_prod_histo,
"label_histo": label_histo,
"surplus_histo": data_surplus_histo,
}
return cdc_jour
# ------------------------------------------------------
# Functions to manage route
# ------------------------------------------------------
self,
date_start=None,
date_end=None,
partner_id=None,
):
"""
Fonction appelée pour l'affichage des courbes consommation
sur le portail
:param scale: type d'affichage des graphes
@returns: dictionnaire pour la construction des graphes
date_start = datetime.strptime(date_start, "%d/%m/%Y")
date_end = datetime.strptime(date_end, "%d/%m/%Y")
date_end = date_utils.end_of(date_end, "day")
scale, step_courbe, step_display_courbe = self.get_step_from_date(
date_start=date_start, date_end=date_end, scale=False
acc_counter_ids = (
self.env["acc.counter"]
.sudo()
.search([("acc_operation_id", "=", self.id)])
# Get PRM ids
if prm_id:
acc_counter_ids = self.env["acc.counter"].browse(prm_id)
elif partner_id:
acc_counter_ids = self.env["acc.counter"].search(
[("partner_id", "=", partner_id)]
)
else:
acc_counter_ids = self.acc_delivery_ids + self.acc_injection_ids
if scale == "week" or scale == "day":
is_curve_line = True
chart_data = {}
if data_type == "cons" or data_type == "pmo":
chart_data_cons = self.get_cdc_by_query_cons(
step_courbe, date_start, date_end, acc_counter_ids
if scale == "week":
chart_data_histo = self.get_cdc_by_query_histo_cons(
"day", date_start, date_end, acc_counter_ids
)
chart_data_cons.update(chart_data_histo)
chart_data.update(chart_data_cons)
if data_type == "prod" or data_type == "pmo":
chart_data_prod = self.get_cdc_by_query_prod(
step_courbe, date_start, date_end, acc_counter_ids
if scale == "week":
chart_data_histo = self.get_cdc_by_query_histo_prod(
"day", date_start, date_end, acc_counter_ids
)
chart_data_prod.update(chart_data_histo)
chart_data.update(chart_data_prod)
last_record = self.get_the_last_day()
date_deb, date_max = self.get_last_day("day", last_record)
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,