feat: Add Analytics, Odoo Integration, A/B Testing, and Content features
Phase 1 - Analytics y Reportes: - PostMetrics and AnalyticsReport models for tracking engagement - Analytics service with dashboard stats, top posts, optimal times - 8 API endpoints at /api/analytics/* - Interactive dashboard with Chart.js charts - Celery tasks for metrics fetch (15min) and weekly reports Phase 2 - Integración Odoo: - Lead and OdooSyncLog models for CRM integration - Odoo fields added to Product and Service models - XML-RPC service for bidirectional sync - Lead management API at /api/leads/* - Leads dashboard template - Celery tasks for product/service sync and lead export Phase 3 - A/B Testing y Recycling: - ABTest, ABTestVariant, RecycledPost models - Statistical winner analysis using chi-square test - Content recycling with engagement-based scoring - APIs at /api/ab-tests/* and /api/recycling/* - Automated test evaluation and content recycling tasks Phase 4 - Thread Series y Templates: - ThreadSeries and ThreadPost models for multi-post threads - AI-powered thread generation - Enhanced ImageTemplate with HTML template support - APIs at /api/threads/* and /api/templates/* - Thread scheduling with reply chain support Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
79
app/models/odoo_sync_log.py
Normal file
79
app/models/odoo_sync_log.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
Odoo Sync Log Model - Track synchronization history with Odoo.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, JSON
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class OdooSyncLog(Base):
|
||||
"""
|
||||
Log of synchronization operations with Odoo ERP.
|
||||
"""
|
||||
__tablename__ = "odoo_sync_logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
# Sync operation details
|
||||
sync_type = Column(String(50), nullable=False, index=True)
|
||||
# Types: products, services, leads, sales
|
||||
|
||||
direction = Column(String(20), nullable=False)
|
||||
# Direction: import (from Odoo), export (to Odoo)
|
||||
|
||||
status = Column(String(20), nullable=False, index=True)
|
||||
# Status: started, completed, failed, partial
|
||||
|
||||
# Statistics
|
||||
records_processed = Column(Integer, default=0)
|
||||
records_created = Column(Integer, default=0)
|
||||
records_updated = Column(Integer, default=0)
|
||||
records_failed = Column(Integer, default=0)
|
||||
|
||||
# Error details
|
||||
error_message = Column(Text, nullable=True)
|
||||
error_details = Column(JSON, nullable=True)
|
||||
# Contains list of failed records with error details
|
||||
|
||||
# Sync details
|
||||
sync_filter = Column(JSON, nullable=True)
|
||||
# Filters applied during sync (e.g., date range, categories)
|
||||
|
||||
# Timestamps
|
||||
started_at = Column(DateTime, default=datetime.utcnow)
|
||||
completed_at = Column(DateTime, nullable=True)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OdooSyncLog {self.id} - {self.sync_type} {self.status}>"
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary."""
|
||||
return {
|
||||
"id": self.id,
|
||||
"sync_type": self.sync_type,
|
||||
"direction": self.direction,
|
||||
"status": self.status,
|
||||
"records_processed": self.records_processed,
|
||||
"records_created": self.records_created,
|
||||
"records_updated": self.records_updated,
|
||||
"records_failed": self.records_failed,
|
||||
"error_message": self.error_message,
|
||||
"error_details": self.error_details,
|
||||
"started_at": self.started_at.isoformat() if self.started_at else None,
|
||||
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
|
||||
"duration_seconds": (self.completed_at - self.started_at).total_seconds() if self.completed_at and self.started_at else None
|
||||
}
|
||||
|
||||
def mark_completed(self):
|
||||
"""Mark sync as completed."""
|
||||
self.status = "completed"
|
||||
self.completed_at = datetime.utcnow()
|
||||
|
||||
def mark_failed(self, error_message: str, details: dict = None):
|
||||
"""Mark sync as failed with error details."""
|
||||
self.status = "failed"
|
||||
self.error_message = error_message
|
||||
self.error_details = details
|
||||
self.completed_at = datetime.utcnow()
|
||||
Reference in New Issue
Block a user