bemade-addons/odoo_to_odoo_bemade_customer/models/sync_config.py
mathis b792e43873 [IMP] Odoo Sync Modules: Major Enhancements and Fixes
- Added comprehensive README files for all three sync modules
- Implemented advanced logging system with multiple log levels (DEBUG, INFO, WARNING, ERROR)
- Added automatic sensitive data masking for security in log payloads
- Implemented log retention policy (90 days local, 7 years in AWS S3 Glacier)
- Added AWS S3 integration for long-term log archiving
- Fixed validation error with bemade_instance_id in sync model creation
- Refactored model inheritance structure from _inherit to _inherits for proper delegation
- Fixed duplicate sync model prevention logic
- Restored Test Connection button in instance view
- Fixed connection test logging to properly record success/failure
- Fixed queue creation for connection test logs
- Removed unnecessary Synchronized Module tab from odoo_to_odoo_bemade
- Added database indexing on create_date for performance optimization
- Fixed foreign key constraint violations in field mappings creation
- Enhanced error handling throughout the synchronization process
2025-08-15 08:40:17 -04:00

202 lines
6.4 KiB
Python

# Copyright 2025 Bemade
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html)
"""Bemade Synchronization Configuration.
This module handles the connection configuration specifically designed for
connecting to Odoo.bemade.org. It provides a simplified interface for clients
to establish and maintain a connection with the Bemade platform.
"""
import logging
import xmlrpc.client
import uuid
from odoo import api, fields, models, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
BEMADE_URL = "https://odoo.bemade.org"
class OdooToBemadeCustomerConfig(models.Model):
"""Bemade connection configuration.
This model stores client-specific connection information for Bemade platform.
It is designed to be simple and focused, with most parameters pre-configured.
"""
_name = 'odoo.to.bemade.customer.config'
_description = 'Configuration Bemade'
name = fields.Char(
string='Nom',
default='Connexion Bemade',
readonly=True,
)
client_key = fields.Char(
string='Clé Client',
required=True,
help='Clé unique fournie par Bemade pour votre instance',
)
api_key = fields.Char(
string='Clé API',
required=True,
help='Clé API fournie par Bemade pour l\'authentification',
)
company_name = fields.Char(
string='Nom de l\'entreprise',
help='Nom de votre entreprise tel qu\'il apparaît chez Bemade',
)
state = fields.Selection(
selection=[
('draft', 'Non configuré'),
('testing', 'Test de connexion'),
('connected', 'Connecté'),
('error', 'Erreur')
],
default='draft',
string='État',
readonly=True,
)
last_sync = fields.Datetime(
string='Dernière synchronisation',
readonly=True,
)
error_message = fields.Text(
string='Message d\'erreur',
readonly=True,
)
sync_models = fields.One2many(
comodel_name='odoo.to.bemade.customer.sync.model',
inverse_name='config_id',
string='Modèles synchronisés',
readonly=True,
)
instance_id = fields.Char(
string='ID Instance',
readonly=True,
help='Identifiant unique de cette instance',
default=lambda self: str(uuid.uuid4()),
)
active = fields.Boolean(
string='Actif',
default=True,
)
auto_configure = fields.Boolean(
string='Configuration automatique',
default=True,
help='Configurer automatiquement les modèles à synchroniser',
)
@api.model
def create(self, vals):
"""Limiter à une seule configuration active"""
existing = self.search([('active', '=', True)])
if existing:
raise UserError(_("Une configuration Bemade existe déjà. Vous ne pouvez avoir qu'une seule configuration active."))
return super().create(vals)
def test_connection(self):
"""Tester la connexion avec Bemade"""
self.ensure_one()
self.state = 'testing'
try:
# Endpoint spécifique pour valider les clés client
common = xmlrpc.client.ServerProxy(f'{BEMADE_URL}/xmlrpc/2/common')
result = common.validate_client(self.client_key, self.api_key, self.instance_id)
if not result.get('success'):
raise UserError(result.get('message', 'Échec de validation des clés'))
# Mise à jour des informations
self.write({
'state': 'connected',
'company_name': result.get('company_name', self.company_name),
'error_message': False
})
# Si autoconfiguration est activée
if self.auto_configure:
self._configure_sync_models(result.get('models', []))
return True
except Exception as e:
self.write({
'state': 'error',
'error_message': str(e)
})
return False
def _configure_sync_models(self, models_data):
"""Configure les modèles à synchroniser basés sur les données de Bemade"""
model_obj = self.env['client.bemade.sync.model']
# Supprimer les anciens modèles
self.sync_models.unlink()
# Créer les nouveaux modèles
for model_data in models_data:
model_obj.create({
'config_id': self.id,
'name': model_data.get('name'),
'model': model_data.get('model'),
'bemade_model': model_data.get('bemade_model'),
'active': True,
'priority': model_data.get('priority', 10),
})
def get_connection(self):
"""Établir une connexion avec Bemade"""
self.ensure_one()
if self.state != 'connected':
self.test_connection()
if self.state != 'connected':
raise UserError(f"Impossible de se connecter à Bemade: {self.error_message}")
# Utiliser l'authentification par clé API
common = xmlrpc.client.ServerProxy(f'{BEMADE_URL}/xmlrpc/2/common')
uid = common.authenticate_client(self.client_key, self.api_key, self.instance_id)
if not uid:
raise UserError("Échec d'authentification avec Bemade")
models = xmlrpc.client.ServerProxy(f'{BEMADE_URL}/xmlrpc/2/object')
return models, uid
def reset_configuration(self):
"""Réinitialiser la configuration"""
self.ensure_one()
return self.write({
'state': 'draft',
'error_message': False
})
def action_sync_now(self):
"""Déclencher une synchronisation immédiate"""
self.ensure_one()
if self.state != 'connected':
raise UserError("Veuillez établir une connexion avant de synchroniser")
# Appeler le gestionnaire de synchronisation
return self.env['odoo.to.bemade.customer.sync.manager'].sync_all()
@api.model
def get_config(self):
"""Récupérer la configuration active"""
config = self.search([('active', '=', True)], limit=1)
if not config:
return False
return config