644 lines
29 KiB
Python
644 lines
29 KiB
Python
"""
|
|
Service layer for Pedimentos CRUD operations
|
|
"""
|
|
|
|
import logging
|
|
import re
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from sqlalchemy import desc, func
|
|
from sqlalchemy.orm import Session, joinedload
|
|
from sqlalchemy.orm import selectinload
|
|
from sqlalchemy.exc import IntegrityError
|
|
from datetime import datetime
|
|
|
|
from api.v1.modules.a76.audit_log.models import AuditLog
|
|
from api.v1.modules.a76.audit_log.services.service import AuditService
|
|
from core.context import get_user_context
|
|
from ..dtos.pedimentos import PedimentosCreate, PedimentosUpdate
|
|
|
|
from .pedimento_config_additional import PedimentoConfigAdditionalService
|
|
from .pedimento_config_calculations import PedimentoConfigCalculationsService
|
|
from .pedimento_config_parameters import PedimentoConfigParametersService
|
|
from .pedimento_config_surcharges import PedimentoConfigSurchargesService
|
|
from .pedimento_config_update_rectification import PedimentoConfigUpdateRectificationService
|
|
from .pedimento_config_updates import PedimentoConfigUpdatesService
|
|
from .pedimento_customs_offices import PedimentoCustomsOfficesService
|
|
from .pedimento_dates import PedimentoDatesService
|
|
from .pedimento_decrementables import PedimentoDecrementablesService
|
|
from .pedimento_incrementables import PedimentoIncrementablesService
|
|
from .pedimento_indexes import PedimentoIndexesService
|
|
from .pedimento_payments import PedimentoPaymentsService
|
|
from .pedimento_rectification_destination import PedimentoRectificationDestinationService
|
|
from .pedimento_rectification_origin import PedimentoRectificationOriginService
|
|
from .pedimento_transport_means import PedimentoTransportMeansService
|
|
from .pedimento_validation import PedimentoValidationService
|
|
|
|
# Crear tablas relacionadas si existen datos
|
|
from ..models.pedimentos import Pedimentos
|
|
from ..models.pedimento_dates import PedimentoDates
|
|
from ..models.pedimento_decrementables import PedimentoDecrementables
|
|
from ..models.pedimento_incrementables import PedimentoIncrementables
|
|
from ..models.pedimento_indexes import PedimentoIndexes
|
|
from ..models.pedimento_validation import PedimentoValidation
|
|
from ..models.pedimento_customs_offices import PedimentoCustomsOffices
|
|
from ..models.pedimento_payments import PedimentoPayments
|
|
from ..models.pedimento_rectification_destination import PedimentoRectificationDestination
|
|
from ..models.pedimento_rectification_origin import PedimentoRectificationOrigin
|
|
from ..models.pedimento_transport_means import PedimentoTransportMeans
|
|
from ..models.pedimento_config_additional import PedimentoConfigAdditional
|
|
from ..models.pedimento_config_calculations import PedimentoConfigCalculations
|
|
from ..models.pedimento_config_parameters import PedimentoConfigParameters
|
|
from ..models.pedimento_config_surcharges import PedimentoConfigSurcharges
|
|
from ..models.pedimento_config_update_rectification import PedimentoConfigUpdateRectification
|
|
from ..models.pedimento_config_updates import PedimentoConfigUpdates
|
|
from ..models.pedimento_packages import PedimentoPackages
|
|
from ..models.pedimento_transport_carriers import PedimentoTransportCarriers
|
|
from ..models.pedimento_seals import PedimentoSeals
|
|
from ..models.pedimento_containers import PedimentoContainers
|
|
from ..models.pedimento_guides import PedimentoGuides
|
|
from ..models.pedimento_contributions import PedimentoContributions
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _ensure_create_audit_log(
|
|
db: Session, *, table_name: str, record_id: str, record_data: Dict[str, Any], username: str, tenant_id: int, company_id: int
|
|
) -> None:
|
|
"""
|
|
Backup audit writer: inserts CREATE log only when listener did not.
|
|
"""
|
|
exists = (
|
|
db.query(AuditLog.spec_id)
|
|
.filter(
|
|
AuditLog.table_name == table_name,
|
|
AuditLog.operation_type == "CREATE",
|
|
AuditLog.record_id == record_id,
|
|
AuditLog.tenant_id == tenant_id,
|
|
AuditLog.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
if exists:
|
|
return
|
|
|
|
AuditService.log_crud_operation(
|
|
db=db,
|
|
table_name=table_name,
|
|
operation_type="CREATE",
|
|
record_data=record_data,
|
|
username=username,
|
|
record_id=record_id,
|
|
company_id=company_id,
|
|
tenant_id=tenant_id,
|
|
)
|
|
db.commit()
|
|
|
|
|
|
def _get_current_username() -> str:
|
|
try:
|
|
context = get_user_context()
|
|
if context:
|
|
return (
|
|
context.get("preferred_username")
|
|
or context.get("email")
|
|
or context.get("sub")
|
|
or "System"
|
|
)
|
|
except Exception:
|
|
pass
|
|
return "System"
|
|
|
|
|
|
class PedimentosService:
|
|
"""Service class for Pedimentos business logic"""
|
|
|
|
@staticmethod
|
|
def get_all(
|
|
db: Session,
|
|
tenant_id: int,
|
|
company_id: Optional[int],
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
filters: Optional[Dict[str, Any]] = None,
|
|
sort_by: Optional[str] = None,
|
|
sort_order: Optional[str] = "asc",
|
|
) -> tuple[List[Pedimentos], int]:
|
|
"""
|
|
Get all pedimentos for a tenant with pagination and filters
|
|
|
|
Args:
|
|
db: Database session
|
|
tenant_id: Tenant ID
|
|
company_id: Optional Company ID
|
|
skip: Number of records to skip
|
|
limit: Maximum number of records to return
|
|
filters: Optional filters dict
|
|
|
|
Returns:
|
|
Tuple of (list of pedimentos, total count)
|
|
"""
|
|
query = db.query(Pedimentos).filter(Pedimentos.tenant_id == tenant_id)
|
|
|
|
if company_id is not None:
|
|
query = query.filter(Pedimentos.company_id == company_id)
|
|
|
|
if filters:
|
|
if filters.get("status"):
|
|
query = query.filter(Pedimentos.status == filters["status"])
|
|
if filters.get("client_id"):
|
|
query = query.filter(Pedimentos.client_id == filters["client_id"])
|
|
if filters.get("year"):
|
|
query = query.filter(Pedimentos.year == filters["year"])
|
|
if filters.get("pedimento"):
|
|
raw_value = str(filters["pedimento"])
|
|
# Normalizar: dejar solo dígitos (ignorar guiones, espacios, etc.)
|
|
normalized = re.sub(r"\D", "", raw_value)
|
|
if normalized:
|
|
ped_key_expr = func.concat(
|
|
func.coalesce(Pedimentos.year, ""),
|
|
func.coalesce(func.substr(Pedimentos.customs_office, 1, 2), ""),
|
|
func.coalesce(Pedimentos.license, ""),
|
|
func.coalesce(Pedimentos.pedimento_number, ""),
|
|
)
|
|
query = query.filter(ped_key_expr.ilike(f"%{normalized}%"))
|
|
|
|
total = query.count()
|
|
|
|
# Eager load all relationships for the response schema
|
|
items = (
|
|
query.options(
|
|
selectinload(Pedimentos.pedimento_dates),
|
|
selectinload(Pedimentos.pedimento_decrementables),
|
|
selectinload(Pedimentos.pedimento_incrementables),
|
|
selectinload(Pedimentos.pedimento_indexes),
|
|
selectinload(Pedimentos.pedimento_validation),
|
|
selectinload(Pedimentos.pedimento_customs_offices),
|
|
selectinload(Pedimentos.pedimento_payments),
|
|
selectinload(Pedimentos.pedimento_rectification_destination),
|
|
selectinload(Pedimentos.pedimento_rectification_origin),
|
|
selectinload(Pedimentos.pedimento_transport_means),
|
|
selectinload(Pedimentos.pedimento_config_additional),
|
|
selectinload(Pedimentos.pedimento_config_calculations),
|
|
selectinload(Pedimentos.pedimento_config_parameters),
|
|
selectinload(Pedimentos.pedimento_config_surcharges),
|
|
selectinload(Pedimentos.pedimento_config_update_rectification),
|
|
selectinload(Pedimentos.pedimento_config_updates),
|
|
selectinload(Pedimentos.pedimento_packages),
|
|
selectinload(Pedimentos.pedimento_transport_carriers),
|
|
selectinload(Pedimentos.pedimento_guides),
|
|
selectinload(Pedimentos.pedimento_contributions),
|
|
selectinload(Pedimentos.pedimento_seals),
|
|
selectinload(Pedimentos.pedimento_containers),
|
|
)
|
|
)
|
|
|
|
# Apply sorting
|
|
if sort_by:
|
|
column = getattr(Pedimentos, sort_by, None)
|
|
if column:
|
|
if sort_order == "desc":
|
|
query = query.order_by(column.desc())
|
|
else:
|
|
query = query.order_by(column.asc())
|
|
else:
|
|
# Default sorting
|
|
query = query.order_by(desc(Pedimentos.created_at))
|
|
|
|
items = query.offset(skip).limit(limit).all()
|
|
|
|
return items, total
|
|
|
|
@staticmethod
|
|
def get_by_id(
|
|
db: Session, pedimento_id: int, tenant_id: int, company_id: int = None
|
|
) -> Optional[Pedimentos]:
|
|
"""
|
|
Get a pedimento by ID
|
|
|
|
Args:
|
|
db: Database session
|
|
pedimento_id: Pedimento ID
|
|
tenant_id: Tenant ID
|
|
company_id: Company ID (optional for backwards compatibility)
|
|
|
|
Returns:
|
|
Pedimento or None if not found
|
|
"""
|
|
query = db.query(Pedimentos).filter(
|
|
Pedimentos.id == pedimento_id, Pedimentos.tenant_id == tenant_id
|
|
)
|
|
|
|
if company_id is not None:
|
|
query = query.filter(Pedimentos.company_id == company_id)
|
|
|
|
# Eager load all relationships for the response schema
|
|
query = query.options(
|
|
selectinload(Pedimentos.pedimento_dates),
|
|
selectinload(Pedimentos.pedimento_decrementables),
|
|
selectinload(Pedimentos.pedimento_incrementables),
|
|
selectinload(Pedimentos.pedimento_indexes),
|
|
selectinload(Pedimentos.pedimento_validation),
|
|
selectinload(Pedimentos.pedimento_customs_offices),
|
|
selectinload(Pedimentos.pedimento_payments),
|
|
selectinload(Pedimentos.pedimento_rectification_destination),
|
|
selectinload(Pedimentos.pedimento_rectification_origin),
|
|
selectinload(Pedimentos.pedimento_transport_means),
|
|
selectinload(Pedimentos.pedimento_config_additional),
|
|
selectinload(Pedimentos.pedimento_config_calculations),
|
|
selectinload(Pedimentos.pedimento_config_parameters),
|
|
selectinload(Pedimentos.pedimento_config_surcharges),
|
|
selectinload(Pedimentos.pedimento_config_update_rectification),
|
|
selectinload(Pedimentos.pedimento_config_updates),
|
|
selectinload(Pedimentos.pedimento_packages),
|
|
selectinload(Pedimentos.pedimento_transport_carriers),
|
|
selectinload(Pedimentos.pedimento_guides),
|
|
selectinload(Pedimentos.pedimento_contributions),
|
|
selectinload(Pedimentos.pedimento_seals),
|
|
selectinload(Pedimentos.pedimento_containers),
|
|
)
|
|
|
|
return query.first()
|
|
|
|
@staticmethod
|
|
def create(
|
|
db: Session, pedimento_data: PedimentosCreate, tenant_id: int, company_id: int
|
|
) -> Pedimentos:
|
|
"""
|
|
Create a new pedimento with related tables
|
|
|
|
Args:
|
|
db: Database session
|
|
pedimento_data: Pedimento creation data
|
|
tenant_id: Tenant ID
|
|
company_id: Company ID
|
|
|
|
Returns:
|
|
Created pedimento
|
|
"""
|
|
try:
|
|
# Check for existing pedimento with same key (Year, Aduana, Patente, Number)
|
|
# This avoids IntegrityError in many cases and provides a better error message.
|
|
existing = db.query(Pedimentos).filter(
|
|
Pedimentos.tenant_id == tenant_id,
|
|
Pedimentos.company_id == company_id,
|
|
Pedimentos.year == pedimento_data.year,
|
|
Pedimentos.customs_office == pedimento_data.customs_office,
|
|
Pedimentos.license == pedimento_data.license,
|
|
Pedimentos.pedimento_number == pedimento_data.pedimento_number,
|
|
Pedimentos.deleted_at.is_(None)
|
|
).first()
|
|
|
|
if existing:
|
|
raise ValueError(
|
|
f"Ya existe un pedimento con estos datos: {pedimento_data.year}-{pedimento_data.customs_office}-{pedimento_data.license}-{pedimento_data.pedimento_number}"
|
|
)
|
|
|
|
# Extraer datos de tablas relacionadas
|
|
|
|
# Extraer datos de tablas relacionadas
|
|
related_data = {
|
|
'pedimento_dates': pedimento_data.pedimento_dates,
|
|
'pedimento_decrementables': pedimento_data.pedimento_decrementables,
|
|
'pedimento_incrementables': pedimento_data.pedimento_incrementables,
|
|
'pedimento_indexes': pedimento_data.pedimento_indexes,
|
|
'pedimento_validation': pedimento_data.pedimento_validation,
|
|
'pedimento_customs_offices': pedimento_data.pedimento_customs_offices,
|
|
'pedimento_payments': pedimento_data.pedimento_payments,
|
|
'pedimento_rectification_destination': pedimento_data.pedimento_rectification_destination,
|
|
'pedimento_rectification_origin': pedimento_data.pedimento_rectification_origin,
|
|
'pedimento_transport_means': pedimento_data.pedimento_transport_means,
|
|
'pedimento_config_additional': pedimento_data.pedimento_config_additional,
|
|
'pedimento_config_calculations': pedimento_data.pedimento_config_calculations,
|
|
'pedimento_config_parameters': pedimento_data.pedimento_config_parameters,
|
|
'pedimento_config_surcharges': pedimento_data.pedimento_config_surcharges,
|
|
'pedimento_config_update_rectification': pedimento_data.pedimento_config_update_rectification,
|
|
'pedimento_config_updates': pedimento_data.pedimento_config_updates,
|
|
'pedimento_packages': pedimento_data.pedimento_packages,
|
|
'pedimento_transport_carriers': pedimento_data.pedimento_transport_carriers,
|
|
'pedimento_guides': pedimento_data.pedimento_guides,
|
|
'pedimento_contributions': getattr(pedimento_data, 'pedimento_contributions', None),
|
|
'pedimento_seals': pedimento_data.pedimento_seals,
|
|
'pedimento_containers': pedimento_data.pedimento_containers,
|
|
}
|
|
|
|
# Crear pedimento principal (excluyendo relaciones)
|
|
pedimento_dict = pedimento_data.model_dump(exclude={
|
|
'pedimento_dates', 'pedimento_decrementables', 'pedimento_incrementables',
|
|
'pedimento_indexes', 'pedimento_validation', 'pedimento_customs_offices',
|
|
'pedimento_payments', 'pedimento_rectification_destination',
|
|
'pedimento_rectification_origin', 'pedimento_transport_means',
|
|
'pedimento_config_additional', 'pedimento_config_calculations',
|
|
'pedimento_config_parameters', 'pedimento_config_surcharges',
|
|
'pedimento_config_update_rectification', 'pedimento_config_updates',
|
|
'pedimento_packages', 'pedimento_transport_carriers', 'pedimento_guides',
|
|
'pedimento_contributions', 'pedimento_seals', 'pedimento_containers'
|
|
})
|
|
|
|
pedimento = Pedimentos(**pedimento_dict)
|
|
pedimento.tenant_id = tenant_id
|
|
pedimento.company_id = company_id
|
|
|
|
db.add(pedimento)
|
|
db.flush() # Flush para obtener el ID sin commit
|
|
|
|
# Helper function para crear objetos relacionados (uno a uno)
|
|
def create_related(model_class, data, extra_fields=None):
|
|
if data or extra_fields:
|
|
# Inicializar obj_dict desde data si existe, sino como dict vacío
|
|
obj_dict = data.model_dump(exclude_none=True) if data else {}
|
|
# Agregar campos extra si se proporcionan
|
|
if extra_fields:
|
|
obj_dict.update(extra_fields)
|
|
# Solo crear si hay datos significativos (más que solo IDs)
|
|
significant_fields = {k: v for k, v in obj_dict.items()
|
|
if k not in ('pedimento_id', 'tenant_id', 'company_id') and v is not None}
|
|
if not significant_fields and not extra_fields:
|
|
return
|
|
obj = model_class(**obj_dict)
|
|
obj.pedimento_id = pedimento.id
|
|
obj.tenant_id = tenant_id
|
|
obj.company_id = company_id
|
|
db.add(obj)
|
|
|
|
# Crear PedimentoDates con capture_time automático
|
|
create_related(
|
|
PedimentoDates,
|
|
related_data['pedimento_dates'],
|
|
extra_fields={'capture_time': datetime.now().time()}
|
|
)
|
|
create_related(PedimentoDecrementables,
|
|
related_data['pedimento_decrementables'])
|
|
create_related(PedimentoIncrementables,
|
|
related_data['pedimento_incrementables'])
|
|
create_related(PedimentoIndexes, related_data['pedimento_indexes'])
|
|
create_related(PedimentoValidation,
|
|
related_data['pedimento_validation'])
|
|
create_related(PedimentoCustomsOffices,
|
|
related_data['pedimento_customs_offices'])
|
|
create_related(PedimentoPayments,
|
|
related_data['pedimento_payments'])
|
|
create_related(PedimentoRectificationDestination,
|
|
related_data['pedimento_rectification_destination'])
|
|
create_related(PedimentoRectificationOrigin,
|
|
related_data['pedimento_rectification_origin'])
|
|
create_related(PedimentoTransportMeans,
|
|
related_data['pedimento_transport_means'])
|
|
create_related(PedimentoConfigAdditional,
|
|
related_data['pedimento_config_additional'])
|
|
create_related(PedimentoConfigCalculations,
|
|
related_data['pedimento_config_calculations'])
|
|
create_related(PedimentoConfigParameters,
|
|
related_data['pedimento_config_parameters'])
|
|
create_related(PedimentoConfigSurcharges,
|
|
related_data['pedimento_config_surcharges'])
|
|
create_related(PedimentoConfigUpdateRectification,
|
|
related_data['pedimento_config_update_rectification'])
|
|
create_related(PedimentoConfigUpdates,
|
|
related_data['pedimento_config_updates'])
|
|
|
|
# Crear PedimentoPackages (uno a uno)
|
|
create_related(PedimentoPackages, related_data['pedimento_packages'])
|
|
|
|
# Crear relaciones uno a muchos
|
|
def create_many(model_class, items):
|
|
if not items:
|
|
return
|
|
for item in items:
|
|
obj_dict = item.model_dump(exclude_none=True)
|
|
obj = model_class(**obj_dict)
|
|
obj.pedimento_id = pedimento.id
|
|
obj.tenant_id = tenant_id
|
|
obj.company_id = company_id
|
|
db.add(obj)
|
|
|
|
create_many(PedimentoTransportCarriers,
|
|
related_data['pedimento_transport_carriers'])
|
|
create_many(PedimentoGuides, related_data['pedimento_guides'])
|
|
create_many(PedimentoContributions, related_data['pedimento_contributions'])
|
|
create_many(PedimentoSeals, related_data['pedimento_seals'])
|
|
create_many(PedimentoContainers,
|
|
related_data['pedimento_containers'])
|
|
|
|
db.commit()
|
|
db.refresh(pedimento)
|
|
_ensure_create_audit_log(
|
|
db,
|
|
table_name=pedimento.__tablename__,
|
|
record_id=str(pedimento.id),
|
|
record_data={c.name: getattr(pedimento, c.name) for c in Pedimentos.__table__.columns},
|
|
username=_get_current_username(),
|
|
tenant_id=tenant_id,
|
|
company_id=company_id,
|
|
)
|
|
return pedimento
|
|
|
|
except IntegrityError as e:
|
|
db.rollback()
|
|
# Detectar si es un error de integridad de duplicados o similar
|
|
error_msg = str(e.orig).lower()
|
|
|
|
# Case-insensitive check and support for both Spanish and English common error patterns
|
|
is_unique_violation = any(kw in error_msg for kw in [
|
|
'pedimentos_unique_key',
|
|
'unique constraint',
|
|
'duplicate key',
|
|
'duplicada',
|
|
'unicidad',
|
|
'ya existe'
|
|
])
|
|
|
|
if is_unique_violation:
|
|
logger.warning(f"Attempted to create duplicate pedimento or common record: {e}")
|
|
raise ValueError("Ya existe un pedimento o registro relacionado con estos datos. Verifica los campos únicos.")
|
|
|
|
logger.error(f"Integrity error creating pedimento: {e}")
|
|
raise
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error creating pedimento with related data: {e}")
|
|
raise
|
|
|
|
@staticmethod
|
|
def update(
|
|
db: Session, pedimento_id: int, tenant_id: int, pedimento_data: PedimentosUpdate, company_id: int = None
|
|
) -> Optional[Pedimentos]:
|
|
"""
|
|
Update a pedimento and its related tables
|
|
|
|
Args:
|
|
db: Database session
|
|
pedimento_id: Pedimento ID
|
|
tenant_id: Tenant ID
|
|
pedimento_data: Updated data
|
|
company_id: Company ID (optional for backwards compatibility)
|
|
|
|
Returns:
|
|
Updated pedimento or None if not found
|
|
"""
|
|
pedimento = PedimentosService.get_by_id(
|
|
db, pedimento_id, tenant_id, company_id)
|
|
if not pedimento:
|
|
return None
|
|
|
|
# Ensure company_id is set from the existing record
|
|
company_id = pedimento.company_id
|
|
|
|
try:
|
|
# Actualizar campos principales del pedimento
|
|
update_data = pedimento_data.model_dump(exclude_unset=True, exclude={
|
|
'pedimento_dates', 'pedimento_decrementables', 'pedimento_incrementables',
|
|
'pedimento_indexes', 'pedimento_validation', 'pedimento_customs_offices',
|
|
'pedimento_payments', 'pedimento_rectification_destination',
|
|
'pedimento_rectification_origin', 'pedimento_transport_means',
|
|
'pedimento_config_additional', 'pedimento_config_calculations',
|
|
'pedimento_config_parameters', 'pedimento_config_surcharges',
|
|
'pedimento_config_update_rectification', 'pedimento_config_updates',
|
|
'pedimento_packages', 'pedimento_transport_carriers', 'pedimento_guides', 'pedimento_contributions', 'pedimento_seals', 'pedimento_containers'
|
|
})
|
|
|
|
for field, value in update_data.items():
|
|
setattr(pedimento, field, value)
|
|
|
|
db.flush()
|
|
|
|
# Helper function para actualizar o crear objetos relacionados
|
|
def update_or_create_related(service_class, model_class, data_attr):
|
|
# Obtener datos del payload completo (no solo exclude_unset)
|
|
full_data = pedimento_data.model_dump()
|
|
|
|
if data_attr not in full_data:
|
|
return
|
|
|
|
data = full_data[data_attr]
|
|
if not data:
|
|
return
|
|
|
|
existing = None
|
|
if service_class:
|
|
existing = service_class.get_by_pedimento_id(
|
|
db, pedimento_id, tenant_id, company_id)
|
|
else:
|
|
existing = getattr(pedimento, data_attr, None)
|
|
|
|
if existing:
|
|
# Actualizar existente (excluir pedimento_id, tenant_id, company_id)
|
|
# Solo actualizar valores no-None para evitar sobrescribir con None
|
|
for field, value in data.items():
|
|
if hasattr(existing, field) and field not in ('pedimento_id', 'tenant_id', 'company_id'):
|
|
if value is not None:
|
|
setattr(existing, field, value)
|
|
else:
|
|
# Crear nuevo
|
|
obj = model_class(**data)
|
|
obj.pedimento_id = pedimento_id
|
|
obj.tenant_id = tenant_id
|
|
obj.company_id = company_id
|
|
db.add(obj)
|
|
|
|
def upsert_one_to_many(model_class, data_attr):
|
|
full_data = pedimento_data.model_dump()
|
|
if data_attr not in full_data:
|
|
return
|
|
|
|
items = full_data[data_attr]
|
|
if items is None:
|
|
return
|
|
|
|
# Reemplazar completamente la colección por simplicidad
|
|
existing_items = getattr(pedimento, data_attr)
|
|
if existing_items:
|
|
for item in list(existing_items):
|
|
db.delete(item)
|
|
|
|
for item in items:
|
|
obj = model_class(**item)
|
|
obj.pedimento_id = pedimento_id
|
|
obj.tenant_id = tenant_id
|
|
obj.company_id = company_id
|
|
db.add(obj)
|
|
|
|
# Actualizar o crear tablas relacionadas
|
|
update_or_create_related(
|
|
PedimentoDatesService, PedimentoDates, 'pedimento_dates')
|
|
update_or_create_related(
|
|
PedimentoDecrementablesService, PedimentoDecrementables, 'pedimento_decrementables')
|
|
update_or_create_related(
|
|
PedimentoIncrementablesService, PedimentoIncrementables, 'pedimento_incrementables')
|
|
update_or_create_related(
|
|
PedimentoIndexesService, PedimentoIndexes, 'pedimento_indexes')
|
|
update_or_create_related(
|
|
PedimentoValidationService, PedimentoValidation, 'pedimento_validation')
|
|
update_or_create_related(
|
|
PedimentoCustomsOfficesService, PedimentoCustomsOffices, 'pedimento_customs_offices')
|
|
update_or_create_related(
|
|
PedimentoPaymentsService, PedimentoPayments, 'pedimento_payments')
|
|
update_or_create_related(PedimentoRectificationDestinationService,
|
|
PedimentoRectificationDestination, 'pedimento_rectification_destination')
|
|
update_or_create_related(PedimentoRectificationOriginService,
|
|
PedimentoRectificationOrigin, 'pedimento_rectification_origin')
|
|
update_or_create_related(
|
|
PedimentoTransportMeansService, PedimentoTransportMeans, 'pedimento_transport_means')
|
|
update_or_create_related(PedimentoConfigAdditionalService,
|
|
PedimentoConfigAdditional, 'pedimento_config_additional')
|
|
update_or_create_related(PedimentoConfigCalculationsService,
|
|
PedimentoConfigCalculations, 'pedimento_config_calculations')
|
|
update_or_create_related(PedimentoConfigParametersService,
|
|
PedimentoConfigParameters, 'pedimento_config_parameters')
|
|
update_or_create_related(PedimentoConfigSurchargesService,
|
|
PedimentoConfigSurcharges, 'pedimento_config_surcharges')
|
|
update_or_create_related(PedimentoConfigUpdateRectificationService,
|
|
PedimentoConfigUpdateRectification, 'pedimento_config_update_rectification')
|
|
update_or_create_related(
|
|
PedimentoConfigUpdatesService, PedimentoConfigUpdates, 'pedimento_config_updates')
|
|
|
|
# Manejar nuevas relaciones
|
|
update_or_create_related(None, PedimentoPackages, 'pedimento_packages')
|
|
upsert_one_to_many(PedimentoTransportCarriers,
|
|
'pedimento_transport_carriers')
|
|
upsert_one_to_many(PedimentoGuides, 'pedimento_guides')
|
|
upsert_one_to_many(PedimentoContributions, 'pedimento_contributions')
|
|
upsert_one_to_many(PedimentoSeals, 'pedimento_seals')
|
|
upsert_one_to_many(PedimentoContainers, 'pedimento_containers')
|
|
|
|
db.commit()
|
|
db.refresh(pedimento)
|
|
return pedimento
|
|
|
|
except IntegrityError as e:
|
|
db.rollback()
|
|
# Detectar si es un error de pedimento duplicado
|
|
error_msg = str(e.orig)
|
|
if 'pedimentos_unique_key' in error_msg or 'duplicate key value violates unique constraint' in error_msg:
|
|
logger.warning(f"Attempted to update to duplicate pedimento: {e}")
|
|
raise ValueError("Ya existe otro pedimento con estos datos (Año, Aduana, Patente, Número)")
|
|
logger.error(f"Integrity error updating pedimento: {e}")
|
|
raise
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error updating pedimento with related data: {e}")
|
|
raise
|
|
|
|
@staticmethod
|
|
def delete(db: Session, pedimento_id: int, tenant_id: int, company_id: int = None) -> bool:
|
|
"""
|
|
Delete a pedimento
|
|
|
|
Args:
|
|
db: Database session
|
|
pedimento_id: Pedimento ID
|
|
tenant_id: Tenant ID
|
|
company_id: Company ID (optional for backwards compatibility)
|
|
|
|
Returns:
|
|
True if deleted, False if not found
|
|
"""
|
|
pedimento = PedimentosService.get_by_id(
|
|
db, pedimento_id, tenant_id, company_id)
|
|
if not pedimento:
|
|
return False
|
|
|
|
db.delete(pedimento)
|
|
db.commit()
|
|
return True
|