Newer
Older
# © 2019 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import csv
import io
import datetime
import logging
from ftplib import FTP
from odoo import models, fields, exceptions
_logger = logging.getLogger(__name__)
class CgscopRigaOdooImport(models.Model):
"""
Ce modèle permet de logguer les imports de RIGA
vers Odoo
"""
_name = 'riga.odoo.import'
_description = 'Synchronisation RIGA vers Odoo'
_rec_name = 'model_id'
_order = 'create_date desc'
model_id = fields.Many2one(
comodel_name='ir.model',
string='Modèle')
is_sync = fields.Boolean('Synchronisé', default=False)
is_warning = fields.Boolean('Warning', default=False)
log = fields.Text('Log')
is_error = fields.Boolean('Erreur Synchro', default=False)
is_resync = fields.Boolean('Re-Synchronisé', default=False)
filename = fields.Char('Nom du fichier')
# ------------------------------------------------------
# Fonctions génériques
# ------------------------------------------------------
"""
Fonction de récupértion d'ufichier sur un FTP.
Cette fonction prend en paramètre un nom de fichier et recherche
dans le fichier de conf Odoo les login et password, puis dans les
paramètres système l'url et le path pour se connecter et retourner
le fichier binaire souhaité.
: param filename: (string) nom du fichier
@return csv_file: (binary) fichier binaire à traiter
ftp_login = param.login
ftp_pass = param.password
ftp = FTP(param.url, ftp_login, ftp_pass)
# Lecture du fichier
csv_file = io.BytesIO()
ftp.retrbinary(
"RETR " + filename,
csv_file.write)
_logger.info(
"Connecté à l'URL : %s - Path : %s",
return csv_file
except Exception as e:
raise exceptions.Warning(e)
def _read_file(self, model, file, table, primary_key, header_key,
filename, resync=False, log_id=None):
"""
Cette fonction prend en paramètre un fichier CSV et lit
chaque ligne pour mettre à jour la ligne de la table correspondante
si elle existe ou la créer si l'organisme existe
:param model (obj): modèle pour importer les données
:param file (binary): fichier CSV à traiter
:param table (list): liste de tuples de correspondance
('champ_odoo', 'champ_csv')
:param primary_key (string): header du fichier CSV correspondant à la clé
:param parent_id (string): header du fichier CSV pour lequel on va
rechercher l'ID RIGA de l'organisme
:param filename (string): nom du fichier
:param resync (bool): le fichier a été synchronisé manuellement
:param log_id (obj): ojjet à mettre à jour si pas de création
try:
file.seek(0)
# Création du lecteur CSV.
reader = csv.DictReader(
io.TextIOWrapper(file, encoding="utf-8-sig", newline=None),
delimiter=';')
model_obj = self.env[model.model]
crea_nb = 0
maj_nb = 0
log = ""
# Lecture de chaque ligne
for row in reader:
# Création de l'objet
vals = {}
for field in table:
field[0]: self._cast_type(
model=model,
field=field[0],
value=row[field[1]],
relation=field[2])
# Vérification de la ligne dans la base
line = model_obj.search([
['id_riga', '=', row[primary_key]]])
# Si il y a un enregistrement, on met à jour
if line:
line.write(vals)
maj_nb += 1
# Check d'un organisme dans la base
partner = self.env['res.partner'].search([
['id_riga', '=', row[header_key]],
['is_cooperative', '=', True]])
# Si l'organisme existe, on crée un enregistrement
if partner:
vals.update({
'partner_id': partner.id
})
model_obj.create(vals)
crea_nb += 1
else:
log += ("Pas d'enredistrement trouvé pour l'id " +
row[primary_key] + " avec l'id riga " +
row[header_key] + "\n")
# Création du log
'model_id': model.id,
'is_sync': True,
'filename': filename,
'log': ("Import du fichier " + filename +
date_value.strftime(data.suffix) + '.' +
data.riga_extension + " : \n" +
" - Création de " + str(crea_nb) + " lignes\n" +
" - Mise à jour de " + str(maj_nb) + " lignes\n\n" + log),
'is_warning': True if log else False,
}
if not log_id:
self.create(vals)
else:
log_id.update(vals)
except Exception as e:
_logger.error(e.__str__())
# Création du log
'model_id': model.id,
'is_sync': False,
'is_error': True,
'log': str(e)
}
if not log_id:
self.create(vals)
else:
log_id.update(vals)
""" Détermine en fonction du champ la valeur typée à renvoyer
pour l'ORM
:param model : objet modèle de donnée Odoo
:param field : nom du champ
:param value : valeur à caster
@return valeur castée
"""
odoo_field = self.env['ir.model.fields'].search([
['model', '=', model.model],
['name', '=', field]])
field_type = odoo_field.ttype
if value:
if field_type == 'integer':
return int(float(value.replace(',', '.')))
elif field_type == 'float':
return float(value.replace(',', '.'))
date_value = datetime.datetime.strptime(
value, '%d/%m/%Y %H:%M:%S')
return date_value
selection = self.env[model.model]._fields.get(
odoo_field.name).selection
for item in selection:
if item[1] == value:
return item[0]
elif field_type == 'many2one':
return m2o_value
else:
return value
else:
return False
# ------------------------------------------------------
# Import données
# ------------------------------------------------------
def odoo_sync(self):
model_sync = self.env['riga.files.matching'].sudo().search([
['is_active', '=', True]])
self.sync_file(model_sync)
def sync_file(self, model_sync):
"""
Fonction de synchronisation des fichiers CSV RIGA
avec les tables associées Odoo.
La fonction recherche l'ensembles des synchronisations actives
dans la table riga.files.matching, elle transforme la table
de correspondance de string à list puis appelle la fonction
_read_file qui permet d'intégrer ou de metre à jour les valeurs
# Calcul nom du fichier
if model.params_active:
date_value = fields.Datetime.now() + datetime.timedelta(days=model.day)
filename = (model.riga_filename +
date_value.strftime(model.suffix) + '.' +
model.riga_extension)
else:
filename = (model.riga_filename + '.' +
model.riga_extension)
_logger.info(
"Lecture Fichier %s pour le modèle %s",
file=self._get_ftp_file(filename, model.ftp_channel_id),
header_key=model.header_key,
filename=filename)
"""
Fonction appelée pour la resynchronisation d'un log
en erreur
"""
model = self.env['riga.files.matching'].sudo().search([
['model_id', '=', self.model_id.id]])
table = []
for header in model.matching_table_ids:
table.append([header.name, header.riga_name, header.relation])
self._read_file(
model=self.model_id,
file=self._get_ftp_file(self.filename, model.ftp_channel_id),
table=table,
primary_key=model.primary_key,
header_key=model.header_key,
log_id=self,
filename=self.filename)