feat: add fixed asset classes management page and embed functionality
- Implemented a new page for managing fixed asset classes with full CRUD functionality. - Added filtering options for searching classes by code, description, type, and fraction. - Integrated dialogs for inserting, editing, and deleting classes with validation. - Enhanced error handling and user feedback with toast notifications. - Created an embedded iframe for the fixed asset classes page in the merchandise section.
This commit is contained in:
223
backend/api/v1/modules/a24/fa/fa_classes/service.py
Normal file
223
backend/api/v1/modules/a24/fa/fa_classes/service.py
Normal file
@@ -0,0 +1,223 @@
|
||||
"""
|
||||
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)
|
||||
|
||||
logger.info(
|
||||
f"Created fixed asset class {new_fa_class.id} for class_id {new_fa_class.class_id}"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
logger.info(f"Updated fixed asset class {fa_class_id}")
|
||||
|
||||
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()
|
||||
|
||||
logger.info(f"Deleted fixed asset class {fa_class_id}")
|
||||
|
||||
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))
|
||||
Reference in New Issue
Block a user