Skip to content
Extraits de code Groupes Projets
Valider c44ea39c rédigé par Juliana's avatar Juliana
Parcourir les fichiers

[ADD]Pre-commit

parent e9639843
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
......@@ -38,4 +38,3 @@ Maintainer
:target: https://le-filament.com
This module is maintained by Le Filament
# Copyright 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models
from . import wizards
from . import models, wizards
{
'name': "ACC - API Enedis",
'summary': "API Enedis",
'author': "Le Filament",
'website': "https://www.le-filament.com",
'version': '14.0.1.0.1',
'license': "AGPL-3",
'depends': [
'acc_operation'
],
'data': [
"name": "ACC - API Enedis",
"summary": "API Enedis",
"author": "Le Filament",
"website": "https://www.le-filament.com",
"version": "14.0.1.0.1",
"license": "AGPL-3",
"depends": ["acc_operation"],
"data": [
"security/ir.model.access.csv",
# datas
'data/service_cron.xml',
'wizards/acc_operation_wizard_views.xml',
"data/service_cron.xml",
"wizards/acc_operation_wizard_views.xml",
# views
'views/res_config_settings_views.xml',
'views/acc_operation_views.xml',
"views/res_config_settings_views.xml",
"views/acc_operation_views.xml",
# views menu
],
'qweb': [
"qweb": [
# "static/src/xml/*.xml",
],
'installable': True,
'auto_install': False,
"installable": True,
"auto_install": False,
}
# 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, date
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models
class AccOperation(models.Model):
_name = 'acc.operation'
_inherit = ['acc.operation', 'api.enedis']
_name = "acc.operation"
_inherit = ["acc.operation", "api.enedis"]
# ------------------------------------------------------
# Fields declaration
......@@ -38,20 +40,26 @@ class AccOperation(models.Model):
# ------------------------------------------------------
@api.model
def _auto_get_enedis_data(self):
''' This method is called from a cron job.
"""This method is called from a cron job.
It is used to get data from Enedis with API.
'''
records = self.search([
('date_start_contract', '<', date.today()),
('client_id', '!=', False),
('secret_id', '!=', False),
('active', '=', True)
])
"""
records = self.search(
[
("date_start_contract", "<", date.today()),
("client_id", "!=", False),
("secret_id", "!=", False),
("active", "=", True),
]
)
for rec in records:
d = rec.date_start_contract + relativedelta(days=10)
if d.day == date.today().day:
date_today_10 = date.today() - relativedelta(days=10)
first_date = datetime(date_today_10.year, date_today_10.month - 1, rec.date_start_contract.day)
first_date = datetime(
date_today_10.year,
date_today_10.month - 1,
rec.date_start_contract.day,
)
last_date = first_date + relativedelta(months=1, days=-1)
rec.get_curves(first_date.date(), last_date.date())
......@@ -64,17 +72,20 @@ class AccOperation(models.Model):
# Load consommation data by PRM
for delivery_counter_id in self.acc_delivery_ids:
self.definitive_load_curves(date_start, date_end, delivery_counter_id, token=token)
self.definitive_load_curves(
date_start, date_end, delivery_counter_id, token=token
)
# Load production data by PRM
for injection_counter_id in self.acc_injection_ids:
self.definitive_load_curves(date_start, date_end, injection_counter_id, token=token)
self.definitive_load_curves(
date_start, date_end, injection_counter_id, token=token
)
def get_perimeter(self):
for operation in self:
res = operation.perimeter()
operation.perimeter()
# ------------------------------------------------------
# Business methods
# ------------------------------------------------------
# © 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import requests
import logging
import pytz
import json
from datetime import datetime, date
from datetime import date, datetime
from odoo import models, exceptions, fields
import pytz
import requests
from requests.auth import _basic_auth_str
from odoo import _, exceptions, fields, models
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
......@@ -19,8 +18,9 @@ class ApiEnedis(models.AbstractModel):
"""Cet Abstract Model partage l'ensemble des fonctions
de l'API Enedis.
"""
_name = 'api.enedis'
_description = 'Connecteur Enedis'
_name = "api.enedis"
_description = "Connecteur Enedis"
def access_token(self):
"""Retourne un access token valide pour 5 secondes."""
......@@ -30,45 +30,46 @@ class ApiEnedis(models.AbstractModel):
url_enedis = self.env.user.company_id.url_enedis
if not url_enedis:
raise UserError(
"L'API n'est pas configurée. Veuillez rentrer l'URL de l'API dans app -> Configuration -> Configuration")
_(
"L'API n'est pas configurée. Veuillez rentrer "
"l'URL de l'API dans app -> Configuration -> Configuration"
)
)
client_id = self.client_id
secret_id = self.secret_id
auth = _basic_auth_str(client_id, secret_id)
url = url_enedis + 'v1/oauth2/token'
url = url_enedis + "v1/oauth2/token"
headers = {
'Authorization': auth,
'Content-Type': "application/x-www-form-urlencoded"
"Authorization": auth,
"Content-Type": "application/x-www-form-urlencoded",
}
formData = {
'grant_type': 'client_credentials',
"grant_type": "client_credentials",
}
auth_request = requests.post(
url=url,
headers=headers,
data=formData)
auth_request = requests.post(url=url, headers=headers, data=formData)
try:
auth_request.raise_for_status()
except Exception as error:
raise ValueError('Autentication failed: {}'.format(error))
raise ValueError("Autentication failed: {}".format(error))
# Gestion erreur API
if auth_request.status_code not in [200]:
try:
message = auth_request.json().get('error_description')
message = auth_request.json().get("error_description")
except:
message = response.error_description
message = auth_request.error_description
raise exceptions.Warning(
_(
"L'appel url '%s' a échoué\n"
"- Code erreur : %d\n"
"- Message : %s" % (
url,
response.error,
message))
"- Message : %s" % (url, auth_request.error, message)
)
)
response = auth_request.json()
token = response.get('access_token')
token = response.get("access_token")
print("--- token ---", str(token))
return token
......@@ -88,23 +89,17 @@ class ApiEnedis(models.AbstractModel):
url_enedis = self.env.user.company_id.url_enedis
header = {
'Content-Type': 'application/json;charset=UTF-8',
'Accept': 'application/json',
'Authorization': 'Bearer ' + str(token)
}
path = {
# ID De l'opération
'agreement_id': self.name,
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json",
"Authorization": "Bearer " + str(token),
}
try:
if call_type == 'get':
response = requests.get(
url_enedis + url,
headers=header,
params=query)
elif call_type == 'post':
if call_type == "get":
response = requests.get(url_enedis + url, headers=header, params=query)
elif call_type == "post":
response = requests.post(
url_enedis + url,)
url_enedis + url,
)
except Exception as err:
_logger.warning(
"Erreur de connexion. URL: %s",
......@@ -116,19 +111,21 @@ class ApiEnedis(models.AbstractModel):
# Gestion erreur API
if response.status_code not in [200]:
try:
message = response.json().get('error_description')
message = response.json().get("error_description")
except:
message = response.json()
raise exceptions.Warning(
_(
"L'appel url '%s' a échoué\n"
"- Code erreur : %d\n"
"- Message : %s" % (
url,
response.status_code,
message))
"- Message : %s" % (url, response.status_code, message)
)
)
return response
def definitive_load_curves(self, date_start, date_end, usage_point_id=None, token=None):
def definitive_load_curves(
self, date_start, date_end, usage_point_id=None, token=None
):
"""Fonction permettant d'appeler l'API Enedis et retourne les courbes
de chare en fonction d'un intervalle de date
:param date_start: une date de début
......@@ -138,19 +135,24 @@ class ApiEnedis(models.AbstractModel):
à la maille d'une opération ou
d'un PRM en particulier
"""
url = 'v1/collective_self_consumption/agreements/' + self.name + '/definitive_load_curves'
url = (
"v1/collective_self_consumption/agreements/"
+ self.name
+ "/definitive_load_curves"
)
if usage_point_id:
name = usage_point_id.name + '_' + str(date_start) + '_' + str(date_end)
name = usage_point_id.name + "_" + str(date_start) + "_" + str(date_end)
else:
name = self.name + '_' + str(date_start) + '_' + str(date_end)
name = self.name + "_" + str(date_start) + "_" + str(date_end)
log_id = self.env['acc.enedis.cdc'].search([
('name', '=', name),
('acc_operation_id', '=', self.id)
])
log_id = self.env["acc.enedis.cdc"].search(
[("name", "=", name), ("acc_operation_id", "=", self.id)]
)
if not log_id:
self.load_data(url, date_start, date_end, usage_point_id=usage_point_id, token=token)
self.load_data(
url, date_start, date_end, usage_point_id=usage_point_id, token=token
)
return True
......@@ -174,63 +176,69 @@ class ApiEnedis(models.AbstractModel):
counter_id = None
query = {
# Date de début de la période souhaitée.La date est incluse dans la période
'start': date_start,
"start": date_start,
# Date de fin de la période souhaitée.La date est incluse dans la période
'end': date_end,
"end": date_end,
# Type de la courbe (enum)
"type": ['cons,autocons,surplus,prod,complement'],
"type": ["cons,autocons,surplus,prod,complement"],
# Identifiant du PRM
'usage_point_id': usage_point_name
"usage_point_id": usage_point_name,
}
response = self.enedis_get_by_url(
url=url,
call_type='get',
query=query,
token=token)
url=url, call_type="get", query=query, token=token
)
# get the data
curves = response.json().get('curves')
curves = response.json().get("curves")
if curves:
name = usage_point_id.name + '_' + str(date_start) + '_' + str(date_end)
name = usage_point_id.name + "_" + str(date_start) + "_" + str(date_end)
for curve in curves:
type = curve['type']
type = curve["type"]
domain_all = [
('date_slot', '>=', date_start),
('date_slot', '<=', date_end),
('acc_operation_id', '=', self.id),
('comp_data_type', '=', type),
("date_slot", ">=", date_start),
("date_slot", "<=", date_end),
("acc_operation_id", "=", self.id),
("comp_data_type", "=", type),
]
domain_prm = domain_all + [('acc_counter_id', '=', counter_id)]
domain_prm = domain_all + [("acc_counter_id", "=", counter_id)]
acc_enedis_cdc_ids = self.env['acc.enedis.cdc'].search(domain_prm)
acc_enedis_cdc_ids = self.env["acc.enedis.cdc"].search(domain_prm)
record_created = False
for point in curve['interval_reading']:
date_slot = pytz.utc.localize(datetime.strptime(point['timestamp'], "%Y-%m-%dT%H:%M:%SZ"))
for point in curve["interval_reading"]:
date_slot = pytz.utc.localize(
datetime.strptime(point["timestamp"], "%Y-%m-%dT%H:%M:%SZ")
)
date_slot3 = fields.Datetime.to_string(date_slot)
record = acc_enedis_cdc_ids.filtered(lambda l: l.date_slot == fields.Datetime.to_datetime(date_slot3))
record = acc_enedis_cdc_ids.filtered(
lambda l: l.date_slot == fields.Datetime.to_datetime(date_slot3)
)
if not record:
self.env['acc.enedis.cdc'].create({
'name': name,
'acc_operation_id': self.id,
'acc_counter_id': counter_id or False,
'comp_data_type': type,
'power': point['value'],
'date_slot': date_slot3,
})
self.env["acc.enedis.cdc"].create(
{
"name": name,
"acc_operation_id": self.id,
"acc_counter_id": counter_id or False,
"comp_data_type": type,
"power": point["value"],
"date_slot": date_slot3,
}
)
record_created = True
if record_created:
# Logs information loaded
self.env['acc.enedis.import.logs'].create({
'name': name,
'acc_operation_id': self.id,
})
self.env["acc.enedis.import.logs"].create(
{
"name": name,
"acc_operation_id": self.id,
}
)
self.is_data_enedis = True
def perimeter(self):
......@@ -240,43 +248,47 @@ class ApiEnedis(models.AbstractModel):
:return Retourne le périmètre d'une opération donnée
Date de début et fin de contrat
"""
url = 'v1/collective_self_consumption/agreements/' + self.name + '/perimeter'
url = "v1/collective_self_consumption/agreements/" + self.name + "/perimeter"
response = self.enedis_get_by_url(
url=url,
call_type='get',
query=[],
token=None)
url=url, call_type="get", query=[], token=None
)
usage_points = response.json().get('usage_points')
usage_points = response.json().get("usage_points")
for usage_point in usage_points:
usage_id = self.env['acc.counter'].search([
('acc_operation_id', '=', self.id),
('name', '=', usage_point['usage_point_id'])])
usage_id = self.env["acc.counter"].search(
[
("acc_operation_id", "=", self.id),
("name", "=", usage_point["usage_point_id"]),
]
)
if usage_id:
usage_id.write({
'date_start_contract': date.fromisoformat(usage_point['start']),
'date_end_contract': date.fromisoformat(usage_point['end']),
})
usage_id.write(
{
"date_start_contract": date.fromisoformat(usage_point["start"]),
"date_end_contract": date.fromisoformat(usage_point["end"]),
}
)
else:
is_delivery = False
is_injection = False
if usage_point['type'] == 'CONS':
if usage_point["type"] == "CONS":
is_delivery = True
if usage_point['type'] == 'PROD':
if usage_point["type"] == "PROD":
is_injection = True
self.date_start_contract = date.fromisoformat(usage_point['start'])
self.date_end_contract = date.fromisoformat(usage_point['end'])
prm_id = self.env['acc.counter'].create({
'name': usage_point['usage_point_id'],
'is_delivery': is_delivery,
'is_injection': is_injection,
'acc_operation_id': self.id,
'date_start_contract': date.fromisoformat(usage_point['start']),
'date_end_contract': date.fromisoformat(usage_point['end']),
})
self.date_start_contract = date.fromisoformat(usage_point["start"])
self.date_end_contract = date.fromisoformat(usage_point["end"])
self.env["acc.counter"].create(
{
"name": usage_point["usage_point_id"],
"is_delivery": is_delivery,
"is_injection": is_injection,
"acc_operation_id": self.id,
"date_start_contract": date.fromisoformat(usage_point["start"]),
"date_end_contract": date.fromisoformat(usage_point["end"]),
}
)
return True
# 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 odoo import fields, models
class ResCompany(models.Model):
......
# 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 api, fields, models
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
_inherit = "res.config.settings"
url_enedis = fields.Char(
related='company_id.url_enedis',
related="company_id.url_enedis",
string="Url API de la plateforme de production interne",
readonly=False)
readonly=False,
)
# ------------------------------------------------------
# Fields declaration
......
......@@ -12,7 +12,8 @@
string="Périmètre"
type="object"
name="get_perimeter"
attrs="{'invisible':[('client_id','=', False), ('secret_id','=', False)]}"/>
attrs="{'invisible':[('client_id','=', False), ('secret_id','=', False)]}"
/>
<button
string="Récupération des courbes"
type="action"
......
......@@ -8,9 +8,17 @@
<field name="inherit_id" ref="base.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//div[hasclass('settings')]" position="inside">
<div class="acc_settings_block" data-string="ACC" string="ACC" data-key="acc_enedis_api">
<div
class="acc_settings_block"
data-string="ACC"
string="ACC"
data-key="acc_enedis_api"
>
<h2>Connexion Enedis</h2>
<div class="row mt16 o_settings_container" id="acc_selection_settings">
<div
class="row mt16 o_settings_container"
id="acc_selection_settings"
>
<div class="col-12 col-lg-6 o_setting_box" id="url_enedis">
<div class="o_setting_right_pane">
<label string="URL" for="url_enedis" />
......@@ -38,11 +46,13 @@
<field name="context">{'module' : 'acc_enedis_api', 'bin_size': False}</field>
</record>
<menuitem id="menu_acc_general_settings"
<menuitem
id="menu_acc_general_settings"
name="Configuration"
parent="acc_operation.menu_acc_config"
sequence="0"
action="action_acc_config_settings"
groups="base.group_system"/>
groups="base.group_system"
/>
</odoo>
# 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
from odoo import _, fields, models
from odoo.exceptions import UserError
class appOperationWizard(models.TransientModel):
_name = 'acc.operation.wizard'
class AccOperationWizard(models.TransientModel):
_name = "acc.operation.wizard"
_description = "Récupération des courbes pour une date donnée"
# ------------------------------------------------------
......@@ -40,12 +40,14 @@ class appOperationWizard(models.TransientModel):
# ------------------------------------------------------
def get_curves(self):
if (self.date_end - self.date_start).days > 31:
raise UserError(
"L'intervalle de temps ne doit pas dépasser 31 Jours")
raise UserError(_("L'intervalle de temps ne doit pas dépasser 31 Jours"))
context = dict(self._context or {})
if context.get('active_ids', False):
self.env['acc.operation'].browse(context.get('active_ids')).get_curves(self.date_start, self.date_end)
return {'type': 'ir.actions.act_window_close'}
if context.get("active_ids", False):
self.env["acc.operation"].browse(context.get("active_ids")).get_curves(
self.date_start, self.date_end
)
return {"type": "ir.actions.act_window_close"}
# ------------------------------------------------------
# Business methods
# ------------------------------------------------------
......@@ -11,8 +11,17 @@
<field name="date_end" required="1" />
</group>
<footer>
<button class="btn btn-sm btn-primary" name="get_curves" string="Récupérer" type="object" />
<button class="btn btn-sm btn-default" special="cancel" string="Annuler"/>
<button
class="btn btn-sm btn-primary"
name="get_curves"
string="Récupérer"
type="object"
/>
<button
class="btn btn-sm btn-default"
special="cancel"
string="Annuler"
/>
</footer>
</form>
</field>
......
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter