216 lines
6.9 KiB
Python
216 lines
6.9 KiB
Python
"""
|
|
Capa de servicio para lógica de negocio de clases de activos fijos (FA)
|
|
"""
|
|
|
|
import logging
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from fastapi import HTTPException
|
|
from sqlalchemy import and_
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.orm import Session
|
|
|
|
from .dto import FAClassCreateDTO, FAClassResponseDTO, FAClassUpdateDTO
|
|
from .models import QClasses
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FAClassService:
|
|
"""Servicio para gestión de clases de activos fijos"""
|
|
|
|
@staticmethod
|
|
def get_all(
|
|
db: Session,
|
|
tenant_id: int,
|
|
company_id: int,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
filters: Optional[Dict[str, Any]] = None,
|
|
) -> tuple[List[QClasses], int]:
|
|
"""
|
|
Obtener todas las clases de activos fijos con paginación y filtros
|
|
"""
|
|
query = db.query(QClasses).filter(
|
|
QClasses.tenant_id == tenant_id, QClasses.company_id == company_id
|
|
)
|
|
|
|
if filters:
|
|
if filters.get("class_id"):
|
|
query = query.filter(QClasses.class_id == filters["class_id"])
|
|
if filters.get("fda_code"):
|
|
query = query.filter(
|
|
QClasses.fda_code.ilike(f"%{filters['fda_code']}%")
|
|
)
|
|
if filters.get("class_enabled") is not None:
|
|
query = query.filter(
|
|
QClasses.class_enabled == filters["class_enabled"]
|
|
)
|
|
|
|
total = query.count()
|
|
items = query.offset(skip).limit(limit).all()
|
|
|
|
return items, total
|
|
|
|
@staticmethod
|
|
def get_by_id(
|
|
db: Session, fa_class_id: int, tenant_id: int, company_id: int
|
|
) -> Optional[QClasses]:
|
|
"""Obtener una clase de activo fijo por ID"""
|
|
return (
|
|
db.query(QClasses)
|
|
.filter(
|
|
QClasses.id == fa_class_id,
|
|
QClasses.tenant_id == tenant_id,
|
|
QClasses.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
@staticmethod
|
|
def get_by_class_id(
|
|
db: Session, class_id: int, tenant_id: int, company_id: int
|
|
) -> Optional[QClasses]:
|
|
"""Obtener una clase de activo fijo por class_id de a76"""
|
|
return (
|
|
db.query(QClasses)
|
|
.filter(
|
|
QClasses.class_id == class_id,
|
|
QClasses.tenant_id == tenant_id,
|
|
QClasses.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
@staticmethod
|
|
def create(
|
|
db: Session, fa_class_data: FAClassCreateDTO, tenant_id: int, company_id: int
|
|
) -> QClasses:
|
|
"""Crear una nueva clase de activo fijo"""
|
|
try:
|
|
# Verificar que la clase base existe en a76.classes
|
|
from api.v1.modules.a76.classes.models import Class
|
|
|
|
base_class = (
|
|
db.query(Class)
|
|
.filter(
|
|
Class.id == fa_class_data.class_id,
|
|
Class.tenant_id == tenant_id,
|
|
Class.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not base_class:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Base class with id {fa_class_data.class_id} not found"
|
|
)
|
|
|
|
# Verificar que no exista ya una clase de activo fijo para esta clase base
|
|
existing = FAClassService.get_by_class_id(
|
|
db, fa_class_data.class_id, tenant_id, company_id
|
|
)
|
|
if existing:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Fixed asset class already exists for class_id {fa_class_data.class_id}"
|
|
)
|
|
|
|
data_dict = fa_class_data.model_dump()
|
|
|
|
new_fa_class = QClasses(
|
|
**data_dict,
|
|
tenant_id=tenant_id,
|
|
company_id=company_id,
|
|
)
|
|
|
|
db.add(new_fa_class)
|
|
db.commit()
|
|
db.refresh(new_fa_class)
|
|
|
|
return new_fa_class
|
|
|
|
except IntegrityError as e:
|
|
db.rollback()
|
|
logger.error(f"IntegrityError creating fixed asset class: {str(e)}")
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Database constraint violation: {str(e.orig)}"
|
|
)
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error creating fixed asset class: {str(e)}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@staticmethod
|
|
def update(
|
|
db: Session,
|
|
fa_class_id: int,
|
|
tenant_id: int,
|
|
fa_class_data: FAClassUpdateDTO,
|
|
company_id: int,
|
|
) -> QClasses:
|
|
"""Actualizar una clase de activo fijo"""
|
|
fa_class = FAClassService.get_by_id(db, fa_class_id, tenant_id, company_id)
|
|
|
|
if not fa_class:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Fixed asset class {fa_class_id} not found"
|
|
)
|
|
|
|
try:
|
|
update_data = fa_class_data.model_dump(exclude_unset=True)
|
|
|
|
for key, value in update_data.items():
|
|
setattr(fa_class, key, value)
|
|
|
|
db.commit()
|
|
db.refresh(fa_class)
|
|
|
|
return fa_class
|
|
|
|
except IntegrityError as e:
|
|
db.rollback()
|
|
logger.error(f"IntegrityError updating fixed asset class: {str(e)}")
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Database constraint violation: {str(e.orig)}"
|
|
)
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error updating fixed asset class: {str(e)}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
@staticmethod
|
|
def delete(
|
|
db: Session, fa_class_id: int, tenant_id: int, company_id: int
|
|
) -> None:
|
|
"""Eliminar una clase de activo fijo"""
|
|
fa_class = FAClassService.get_by_id(db, fa_class_id, tenant_id, company_id)
|
|
|
|
if not fa_class:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Fixed asset class {fa_class_id} not found"
|
|
)
|
|
|
|
try:
|
|
db.delete(fa_class)
|
|
db.commit()
|
|
|
|
except IntegrityError as e:
|
|
db.rollback()
|
|
logger.error(f"IntegrityError deleting fixed asset class: {str(e)}")
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Cannot delete: Fixed asset class is referenced by other records"
|
|
)
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error deleting fixed asset class: {str(e)}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|