bemade-addons/odoo_to_odoo_bemade_customer/models/sync_model_field.py
2025-05-29 21:35:47 -04:00

117 lines
4 KiB
Python

# Copyright 2025 Bemade
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html)
"""Field Synchronization Configuration for Bemade clients.
This module defines how fields are synchronized between client instances
and the Bemade platform. It simplifies field mapping and transformations
for Bemade customers.
"""
import logging
import json
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
class OdooToBemadeCustomerSyncModelField(models.Model):
"""Champ de modèle synchronisé avec Bemade."""
_name = 'odoo.to.bemade.customer.sync.model.field'
_description = 'Champ de modèle synchronisé avec Bemade'
_inherit = 'odoo.sync.model.field'
sync_model_id = fields.Many2one(
comodel_name='odoo.to.bemade.customer.sync.model',
string='Modèle synchronisé',
required=True,
ondelete='cascade',
help='Modèle auquel ce champ appartient',
)
field_name = fields.Char(
string='Nom du champ',
required=True,
help='Nom technique du champ dans le modèle local (ex: name)'
)
bemade_field_name = fields.Char(
string='Nom du champ Bemade',
required=True,
help='Nom technique du champ correspondant chez Bemade'
)
is_identifier = fields.Boolean(
string='Est un identifiant',
default=False,
help='Indique si ce champ est utilisé pour identifier l\'enregistrement chez Bemade'
)
transform_type = fields.Selection(
selection=[
('none', 'Aucune transformation'),
('function', 'Fonction Python'),
('mapping', 'Mapping de valeurs')
],
string='Type de transformation',
default='none',
required=True,
help='Type de transformation à appliquer au champ lors de la synchronisation'
)
transform_mapping = fields.Text(
string='Mapping de transformation',
help='Mapping JSON pour la transformation des valeurs (format: {"valeur_source": "valeur_cible",...})'
)
transform_function = fields.Text(
string='Fonction de transformation',
help='Code Python pour transformer la valeur (doit retourner la valeur transformée)'
)
active = fields.Boolean(
string='Actif',
default=True,
help='Indique si ce champ est activement synchronisé'
)
@api.constrains('transform_mapping')
def _check_transform_mapping_json(self):
"""Vérifie que le mapping de transformation est un JSON valide."""
for record in self:
if record.transform_mapping:
try:
json.loads(record.transform_mapping)
except json.JSONDecodeError:
raise ValidationError(_("Le mapping de transformation doit être un JSON valide"))
def transform_value(self, value):
"""Transforme une valeur selon la configuration du champ."""
self.ensure_one()
if self.transform_type == 'none' or value is False:
return value
if self.transform_type == 'mapping':
if not self.transform_mapping:
return value
mapping = json.loads(self.transform_mapping)
str_value = str(value)
return mapping.get(str_value, value)
if self.transform_type == 'function':
if not self.transform_function:
return value
# Implémentation sécurisée de l'exécution de code - à améliorer
local_dict = {'value': value, 'result': value}
try:
# pylint: disable=exec-used
exec(self.transform_function, {'__builtins__': {}}, local_dict)
return local_dict.get('result', value)
except Exception as e:
_logger.error("Erreur lors de l'exécution de la fonction de transformation: %s", str(e))
return value