from datetime import datetime, timezone from fastapi import HTTPException, status from sqlalchemy.orm import Session from api.v1.modules.fin.catalogs.models import CfdiUse, TaxRegime from .dto import AccountCreate, AccountUpdate from .models import Account def _validate_sat_refs(db: Session, data: dict) -> None: """Verifica las claves del SAT del receptor antes de guardar la cuenta.""" for field, model, msg in [ ("tax_regime_id", TaxRegime, "El régimen fiscal indicado no existe en el catálogo del SAT"), ("cfdi_use_id", CfdiUse, "El uso de CFDI indicado no existe en el catálogo del SAT"), ]: value = data.get(field) if field in data and value is not None: if db.query(model.id).filter(model.id == value).first() is None: raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=msg) def get_accounts( db: Session, tenant_id: int, company_id: int, search: str | None = None, account_status: str | None = None, record_type: str | None = None, ) -> list[Account]: query = db.query(Account).filter( Account.tenant_id == tenant_id, Account.company_id == company_id, Account.deleted_at.is_(None), ) if search: pattern = f"%{search}%" query = query.filter( Account.name.ilike(pattern) | Account.trade_name.ilike(pattern) | Account.rfc.ilike(pattern) ) if account_status: query = query.filter(Account.status == account_status) if record_type: query = query.filter(Account.record_type == record_type) return query.order_by(Account.name.asc()).all() def get_account(db: Session, account_id: int, tenant_id: int, company_id: int) -> Account: account = ( db.query(Account) .filter( Account.id == account_id, Account.tenant_id == tenant_id, Account.company_id == company_id, Account.deleted_at.is_(None), ) .first() ) if not account: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cliente no encontrado") return account def create_account( db: Session, payload: AccountCreate, tenant_id: int, company_id: int, user_id: str | None = None ) -> Account: data = payload.model_dump() _validate_sat_refs(db, data) account = Account( **data, tenant_id=tenant_id, company_id=company_id, created_by=user_id, updated_by=user_id, ) db.add(account) db.commit() db.refresh(account) return account def update_account( db: Session, account_id: int, payload: AccountUpdate, tenant_id: int, company_id: int, user_id: str | None = None, ) -> Account: account = get_account(db, account_id, tenant_id, company_id) data = payload.model_dump(exclude_unset=True) _validate_sat_refs(db, data) for field, value in data.items(): setattr(account, field, value) account.updated_by = user_id db.commit() db.refresh(account) return account def delete_account(db: Session, account_id: int, tenant_id: int, company_id: int) -> None: account = get_account(db, account_id, tenant_id, company_id) # Soft delete: conserva el histórico comercial del cliente account.deleted_at = datetime.now(timezone.utc) db.commit()