bemade-addons/odoo_to_odoo_sync/models/sync_model.py
mathis 9df769be69 feat: Complete bidirectional sync system with legacy cleanup
BREAKING CHANGE: Legacy API key system (sync.api.key) completely removed

Major Features:
- Complete bidirectional synchronization system between Odoo instances
- Legacy API key system removal and migration to built-in Odoo API keys
- Full protocol support: XML-RPC, JSON-RPC, and OdooRPC with API token authentication
- Bidirectional project sync with assign/receive wizard system
- Auto-sync wizard for intelligent field selection
- Comprehensive test suite for sync workflows

Detailed Changes:

odoo_to_odoo_sync (base module):
- Removed legacy sync.api.key and sync.api.key.log models entirely
- Added sync_project and sync_project_config_wizard models
- Enhanced sync_instance with proper Odoo 18 API key format support
- Added protocol selection (XML-RPC, JSON-RPC, OdooRPC) with API token auth
- Implemented comprehensive authentication with debug logging
- Added test_sync_workflow.py for complete workflow testing
- Updated security access rules for new models
- Enhanced error handling and state management

odoo_to_odoo_bemade (server module):
- Created OdooToBemadeInstance model for enhanced instance management
- Added assign project wizard for server-side project distribution
- Implemented project key and API token generation system
- Added automatic sync model creation for projects and tasks
- Enhanced sync_instance with bidirectional sync capabilities
- Updated views and security access for new functionality
- Removed legacy API key references and views

odoo_to_odoo_bemade_customer (client module):
- Added project model with Bemade sync flags (is_bemade_project, bemade_project_key)
- Created receive project wizard for client-side project acquisition
- Implemented multi-protocol support (XML-RPC, JSON-RPC, OdooRPC)
- Added project sync validation and configuration system
- Enhanced security access rules for client operations
- Updated views for project management interface

Authentication & Protocol Support:
- Fixed Odoo 18 API key format: {'scope': 'rpc', 'key': api_token}
- Added comprehensive debug logging for authentication flow
- Enhanced error handling with detailed state management
- Maintained backward compatibility with fallback attempts
- Updated all protocol implementations (XML-RPC, JSON-RPC, OdooRPC)

Testing & Validation:
- Added complete test suite for bidirectional sync workflow
- Implemented comprehensive authentication testing
- Added protocol-specific test cases
- Enhanced error state validation

UI/UX Improvements:
- Added intuitive wizards for project assign/receive operations
- Implemented auto-sync wizard with field selection modes (Full, Required, Balanced)
- Enhanced form views with radio button selections
- Added descriptive text and user guidance

Security:
- Updated security access rules for all new models
- Enhanced authentication token handling
- Added proper model access controls

Migration Notes:
- Legacy API key system completely removed - no migration path needed
- Uses built-in Odoo API key functionality
- All existing configurations remain compatible

Files Added/Modified:
- Multiple new model files for project sync functionality
- Wizard implementations for user workflows
- Enhanced test coverage
- Updated security rules and access controls
- New view definitions for UI components
2025-08-17 08:20:24 -04:00

127 lines
No EOL
3.7 KiB
Python

# Copyright 2025 Codeium
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html)
"""Model Synchronization Configuration.
This module defines how models are synchronized between Odoo instances.
It handles model mapping, field configuration, and synchronization rules
for each model that needs to be synchronized.
"""
import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
class OdooSyncModel(models.Model):
_name = 'odoo.sync.model'
_description = 'Synchronized Model'
_order = 'priority, id'
model_id = fields.Many2one(
comodel_name='ir.model',
string='Source Model',
required=True,
ondelete='cascade'
)
name = fields.Char(
related='model_id.model',
string='Technical Name',
store=True
)
instance_id = fields.Many2one(
comodel_name='odoo.sync.instance',
string='Remote Instance',
required=True
)
project_id = fields.Many2one(
comodel_name='sync.project',
string='Sync Project',
ondelete='cascade'
)
target_model = fields.Char(
string='Target Model',
help='Technical name of the model on remote instance'
)
active = fields.Boolean(
string='Active',
default=True
)
priority = fields.Integer(
string='Priority',
default=10,
help='Synchronization order for dependencies'
)
field_ids = fields.One2many(
comodel_name='odoo.sync.model.field',
inverse_name='model_sync_id',
string='Synchronized Fields'
)
_sql_constraints = [
('model_instance_uniq', 'unique(model_id, instance_id)',
'Un modèle ne peut être synchronisé qu\'une fois par instance!')
]
@api.model
def create(self, vals):
if not vals.get('target_model') and vals.get('model_id'):
# Par défaut, utiliser le même nom de modèle que la source
model = self.env['ir.model'].browse(vals['model_id'])
vals['target_model'] = model.model
record = super().create(vals)
# Créer automatiquement les champs de base
if record.model_id:
fields_to_sync = ['create_date', 'write_date', 'create_uid', 'write_uid']
for field_name in fields_to_sync:
field = self.env['ir.model.fields'].search([
('model_id', '=', record.model_id.id),
('name', '=', field_name)
])
if field:
self.env['odoo.sync.model.field'].create({
'model_sync_id': record.id,
'field_id': field.id,
'required': True
})
return record
def name_get(self):
return [(r.id, f'{r.name}{r.instance_id.name}') for r in self]
def action_auto_sync_fields(self):
"""Open the auto-sync wizard for field selection."""
self.ensure_one()
if not self.model_id:
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': 'Error',
'message': 'No model selected',
'type': 'danger',
'sticky': False,
}
}
return {
'type': 'ir.actions.act_window',
'name': 'Auto Sync Fields',
'res_model': 'odoo.sync.auto.sync.wizard',
'view_mode': 'form',
'target': 'new',
'context': {
'default_sync_model_id': self.id,
},
}