193 lines
6.0 KiB
Python
193 lines
6.0 KiB
Python
import logging
|
|
from typing import List, Optional, Dict, Any, Tuple
|
|
|
|
from fastapi import HTTPException
|
|
from sqlalchemy import or_
|
|
from sqlalchemy.orm import Session
|
|
|
|
from .models import Manifest
|
|
from .dtos import ManifestCreateDTO, ManifestUpdateDTO, ManifestResponseDTO
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ManifestService:
|
|
@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[Manifest], int]:
|
|
query = db.query(Manifest).filter(
|
|
Manifest.tenant_id == tenant_id,
|
|
Manifest.company_id == company_id,
|
|
)
|
|
|
|
if filters:
|
|
if filters.get("search"):
|
|
search_pattern = f"%{filters['search']}%"
|
|
query = query.filter(
|
|
or_(
|
|
Manifest.manifest_number.ilike(search_pattern),
|
|
Manifest.description.ilike(search_pattern),
|
|
)
|
|
)
|
|
|
|
if filters.get("manifest_number"):
|
|
query = query.filter(
|
|
Manifest.manifest_number.ilike(f"%{filters['manifest_number']}%")
|
|
)
|
|
|
|
if filters.get("start_date"):
|
|
query = query.filter(Manifest.entry_date >= filters["start_date"])
|
|
|
|
if filters.get("end_date"):
|
|
query = query.filter(Manifest.entry_date <= filters["end_date"])
|
|
|
|
total = query.count()
|
|
items = query.offset(skip).limit(limit).all()
|
|
|
|
return items, total
|
|
|
|
@staticmethod
|
|
def get_by_id(
|
|
db: Session, manifest_id: int, tenant_id: int, company_id: int
|
|
) -> Optional[Manifest]:
|
|
return (
|
|
db.query(Manifest)
|
|
.filter(
|
|
Manifest.id == manifest_id,
|
|
Manifest.tenant_id == tenant_id,
|
|
Manifest.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
@staticmethod
|
|
def create(
|
|
db: Session,
|
|
manifest_data: ManifestCreateDTO,
|
|
tenant_id: int,
|
|
company_id: int,
|
|
) -> Manifest:
|
|
try:
|
|
db_manifest = Manifest(
|
|
**manifest_data.model_dump(exclude_unset=True),
|
|
tenant_id=tenant_id,
|
|
company_id=company_id,
|
|
)
|
|
db.add(db_manifest)
|
|
db.commit()
|
|
db.refresh(db_manifest)
|
|
return db_manifest
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error creating manifest: {str(e)}")
|
|
raise HTTPException(status_code=500, detail="Error creating manifest")
|
|
|
|
@staticmethod
|
|
def update(
|
|
db: Session,
|
|
manifest_id: int,
|
|
tenant_id: int,
|
|
company_id: int,
|
|
manifest_data: ManifestUpdateDTO,
|
|
) -> Optional[Manifest]:
|
|
manifest = ManifestService.get_by_id(db, manifest_id, tenant_id, company_id)
|
|
if not manifest:
|
|
return None
|
|
|
|
try:
|
|
update_data = manifest_data.model_dump(exclude_unset=True)
|
|
for field, value in update_data.items():
|
|
setattr(manifest, field, value)
|
|
|
|
db.commit()
|
|
db.refresh(manifest)
|
|
return manifest
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error updating manifest {manifest_id}: {str(e)}")
|
|
raise HTTPException(status_code=500, detail="Error updating manifest")
|
|
|
|
@staticmethod
|
|
def delete(
|
|
db: Session, manifest_id: int, tenant_id: int, company_id: int
|
|
) -> bool:
|
|
manifest = ManifestService.get_by_id(db, manifest_id, tenant_id, company_id)
|
|
if not manifest:
|
|
return False
|
|
|
|
try:
|
|
db.delete(manifest)
|
|
db.commit()
|
|
return True
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(f"Error deleting manifest {manifest_id}: {str(e)}")
|
|
raise HTTPException(status_code=500, detail="Error deleting manifest")
|
|
|
|
@staticmethod
|
|
def update_invoice_manifest(
|
|
db: Session,
|
|
invoice_id: int,
|
|
tenant_id: int,
|
|
company_id: int,
|
|
manifest_number: Optional[str],
|
|
) -> bool:
|
|
"""
|
|
Update ONLY the manifest_number of an invoice.
|
|
Creates compliance_mx record if it doesn't exist.
|
|
"""
|
|
# Import models here to avoid circular dependencies if any
|
|
from api.v1.modules.a76.invoices.models import (
|
|
InvoiceHeader,
|
|
InvoiceComplianceMx,
|
|
)
|
|
|
|
invoice = (
|
|
db.query(InvoiceHeader)
|
|
.filter(
|
|
InvoiceHeader.id == invoice_id,
|
|
InvoiceHeader.tenant_id == tenant_id,
|
|
InvoiceHeader.company_id == company_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not invoice:
|
|
return False
|
|
|
|
try:
|
|
if invoice.compliance_mx:
|
|
invoice.compliance_mx.manifest_number = manifest_number
|
|
else:
|
|
# Create new compliance record with defaults for required fields
|
|
new_compliance = InvoiceComplianceMx(
|
|
invoice_id=invoice.id,
|
|
tenant_id=tenant_id,
|
|
company_id=company_id,
|
|
manifest_number=manifest_number,
|
|
# Required fields defaults
|
|
is_pedimento_pending=False,
|
|
is_regime_change=False,
|
|
is_owner_of_goods=False,
|
|
generate_balances=False,
|
|
is_mixed=False,
|
|
)
|
|
db.add(new_compliance)
|
|
|
|
db.commit()
|
|
return True
|
|
except Exception as e:
|
|
db.rollback()
|
|
logger.error(
|
|
f"Error linking invoice {invoice_id} to manifest {manifest_number}: {str(e)}"
|
|
)
|
|
raise HTTPException(
|
|
status_code=500, detail="Error linking invoice to manifest"
|
|
)
|