feat: plantilla base workspace SaaS
Some checks failed
Build Producción & Push a Harbor / test (push) Failing after 3s
Build Producción & Push a Harbor / build (push) Has been skipped
Aduanasoft/plantillas-proyectos/pipeline/head There was a failure building this commit

This commit is contained in:
2026-07-21 13:59:00 -05:00
commit bdd089954b
470 changed files with 70022 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
"""
Módulo de dashboard para estadísticas y métricas empresariales
"""
from .routes import router
__all__ = ["router"]

View File

@@ -0,0 +1,109 @@
"""
DTOs para el dashboard de estadísticas y métricas empresariales
"""
from typing import Dict, List, Optional
from pydantic import BaseModel, Field
from datetime import datetime
class KPIMetric(BaseModel):
"""Métrica individual de KPI"""
label: str = Field(..., description="Nombre del indicador")
value: int | float = Field(..., description="Valor actual")
previous_value: Optional[int | float] = Field(
None, description="Valor anterior para comparación"
)
percentage_change: Optional[float] = Field(None, description="Porcentaje de cambio")
trend: Optional[str] = Field(None, description="up, down, stable")
unit: Optional[str] = Field(None, description="Unidad de medida (%, USD, etc)")
class ActivityItem(BaseModel):
"""Item de actividad reciente"""
id: int
type: str = Field(
..., description="Tipo de actividad: invoice, pedimento, client, etc"
)
title: str = Field(..., description="Título descriptivo")
description: Optional[str] = Field(None, description="Descripción adicional")
timestamp: datetime
status: Optional[str] = Field(None, description="Estado del item")
icon: Optional[str] = Field(None, description="Icono a mostrar")
class ChartDataPoint(BaseModel):
"""Punto de datos para gráficas"""
label: str
value: float
category: Optional[str] = None
class DashboardStats(BaseModel):
"""Estadísticas generales del dashboard"""
# KPIs principales
total_invoices: KPIMetric
total_pedimentos: KPIMetric
total_clients: KPIMetric
total_providers: KPIMetric
active_items: KPIMetric
pending_approvals: KPIMetric
# Estadísticas financieras
total_value_imports: Optional[float] = Field(
None, description="Valor total de importaciones"
)
total_value_exports: Optional[float] = Field(
None, description="Valor total de exportaciones"
)
# Datos para gráficas
invoices_by_month: List[ChartDataPoint] = Field(default_factory=list)
pedimentos_by_month: List[ChartDataPoint] = Field(default_factory=list)
operations_by_type: List[ChartDataPoint] = Field(default_factory=list)
top_clients: List[ChartDataPoint] = Field(default_factory=list)
top_providers: List[ChartDataPoint] = Field(default_factory=list)
# Actividad reciente
recent_activity: List[ActivityItem] = Field(default_factory=list)
# Metadata
generated_at: datetime = Field(default_factory=datetime.utcnow)
company_id: int
company_name: Optional[str] = None
class OperationsOverview(BaseModel):
"""Vista general de operaciones"""
total_operations: int
by_type: Dict[str, int] = Field(default_factory=dict)
by_status: Dict[str, int] = Field(default_factory=dict)
avg_processing_time: Optional[float] = Field(
None, description="Tiempo promedio en días"
)
class InventoryMetrics(BaseModel):
"""Métricas de inventario"""
total_items: int
items_in_stock: int
items_low_stock: int
total_value: Optional[float] = None
by_category: Dict[str, int] = Field(default_factory=dict)
class ComplianceMetrics(BaseModel):
"""Métricas de cumplimiento normativo"""
pending_documents: int
expired_permits: int
upcoming_deadlines: int
compliance_score: Optional[float] = Field(
None, description="Score de cumplimiento 0-100"
)

View File

@@ -0,0 +1,84 @@
"""
Endpoints del dashboard para estadísticas y métricas empresariales
"""
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from core.database import get_core_db
from core.security import get_current_user, validate_access_to_resource
from .dto import DashboardStats, OperationsOverview, InventoryMetrics
from .service import DashboardService
router = APIRouter(prefix="/dashboard", tags=["Dashboard"])
@router.get("/stats", response_model=DashboardStats)
async def get_dashboard_stats(
company_id: int = Query(..., description="Company ID"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
"""
Obtiene estadísticas completas del dashboard para la compañía especificada.
Incluye:
- KPIs principales (facturas, pedimentos, clientes, proveedores, items)
- Gráficas de tendencias (facturas por mes, operaciones por tipo)
- Top clientes y proveedores
- Actividad reciente
"""
# Validar acceso
tenant_id = validate_access_to_resource(db, company_id, current_user)
# Generar estadísticas
service = DashboardService(db, tenant_id, company_id)
stats = service.get_complete_dashboard_stats()
return stats
@router.get("/operations-overview", response_model=OperationsOverview)
async def get_operations_overview(
company_id: int = Query(..., description="Company ID"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
"""
Obtiene una vista general de las operaciones
"""
tenant_id = validate_access_to_resource(db, company_id, current_user)
service = DashboardService(db, tenant_id, company_id)
# Implementación básica
ops_by_type = service.get_operations_by_type()
return OperationsOverview(
total_operations=sum(int(op.value) for op in ops_by_type),
by_type={op.label: int(op.value) for op in ops_by_type},
by_status={},
)
@router.get("/inventory-metrics", response_model=InventoryMetrics)
async def get_inventory_metrics(
company_id: int = Query(..., description="Company ID"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
):
"""
Obtiene métricas de inventario
"""
tenant_id = validate_access_to_resource(db, company_id, current_user)
service = DashboardService(db, tenant_id, company_id)
items_kpi = service.get_items_metrics()
return InventoryMetrics(
total_items=int(items_kpi.value),
items_in_stock=int(items_kpi.value), # Simplificado
items_low_stock=0,
by_category={},
)

View File

@@ -0,0 +1,43 @@
"""
Servicio del dashboard — STUB.
Implementa las métricas de tu proyecto aquí.
"""
from sqlalchemy.orm import Session
from .dto import DashboardStats, KPIMetric, OperationsOverview, InventoryMetrics
class DashboardService:
"""Stub — reemplaza con las consultas de tu proyecto."""
def __init__(self, db: Session, tenant_id: int, company_id: int):
self.db = db
self.tenant_id = tenant_id
self.company_id = company_id
def get_stats(self) -> DashboardStats:
empty_kpi = KPIMetric(label="", value=0, trend="stable")
return DashboardStats(
company_id=self.company_id,
generated_at="",
total_invoices=empty_kpi,
total_pedimentos=empty_kpi,
total_clients=empty_kpi,
total_providers=empty_kpi,
active_items=empty_kpi,
pending_approvals=empty_kpi,
invoices_by_month=[],
operations_by_type=[],
top_clients=[],
top_providers=[],
recent_activity=[],
)
def get_operations_overview(self) -> OperationsOverview:
return OperationsOverview(total_operations=0, by_type={}, by_status={})
def get_inventory_metrics(self) -> InventoryMetrics:
return InventoryMetrics(
total_items=0, items_in_stock=0, items_low_stock=0, by_category={}
)