Spaces:
Paused
Paused
| """ | |
| Report Builders — Transform raw scraper data into structured report models. | |
| Each builder handles a specific report type. | |
| """ | |
| import logging | |
| from typing import Any, Optional | |
| from datetime import datetime, timezone | |
| from app.reports.schemas import ( | |
| ScoreHistorial, ScoreCrediticio, | |
| PersonReport, CompanyReport, Identificacion, Contacto, Domicilio, | |
| DatosFiscales, DatosFinancieros, DatosSocietarios, DatosPatrimoniales, | |
| DatosJudiciales, PublicacionBO, BcraHistorial, ChequeRechazado, | |
| CausaJudicial, Vehiculo, InfraccionTransito, MarcaINPI, Vinculo, | |
| DatosPrevisionales, DatosAcademicos, TituloAcademico, IndicadorRiesgo, | |
| Inmueble, Inhibicion, DatosRegistroCivil, GroupReport, VehicleReport, | |
| PropertyReport, ReportMeta, ActividadFiscal, CompanyIdentificacion, RedSocial, | |
| DatosIGJ, ViasSalud, ContratoEstado, MatriculaProfesional, | |
| DatosBilleterasVirtuales, BilleteraVirtual, TimelineEvent, DeudorAlimentario, Monotributo | |
| ) | |
| from app.reports.schemas import ( | |
| CompanyReport, VehicleReport, PropertyReport, GroupReport | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # ─── Helper Functions ─── | |
| def _safe_get(data: dict, key: str, default=None): | |
| """Obtiene valor de dict de forma segura.""" | |
| if not isinstance(data, dict): | |
| return default | |
| return data.get(key, default) | |
| def _safe_list(data: dict, key: str) -> list: | |
| """Obtiene lista de forma segura.""" | |
| val = _safe_get(data, key) | |
| return val if isinstance(val, list) else [] | |
| def _safe_dict(data: dict, key: str) -> dict: | |
| val = _safe_get(data, key) | |
| return val if isinstance(val, dict) else {} | |
| # ─── Builders ─── | |
| def build_identificacion(data: dict, cuit: str) -> Identificacion: | |
| """Construye sección de identificación.""" | |
| return Identificacion( | |
| cuit=cuit, | |
| tipo_clave=_safe_get(data, "tipo_clave"), | |
| tipo_documento=_safe_get(data, "tipo_documento"), | |
| numero_documento=_safe_get(data, "numero_documento"), | |
| nombres=_safe_get(data, "nombres"), | |
| apellido=_safe_get(data, "apellido"), | |
| nombres_completo=_safe_get(data, "nombres_completo"), | |
| fecha_nacimiento=_safe_get(data, "fecha_nacimiento"), | |
| fecha_fallecimiento=_safe_get(data, "fecha_fallecimiento"), | |
| sexo=_safe_get(data, "sexo"), | |
| ) | |
| def build_contacto(data: dict) -> Contacto: | |
| """Construye sección de contacto.""" | |
| # Intentar desde redes sociales | |
| redes = _safe_list(data.get("redes_sociales", {}), "redes_sociales") if isinstance(data.get("redes_sociales"), dict) else _safe_list(data, "redes_sociales") | |
| emails = [] | |
| phones = [] | |
| for r in redes: | |
| if isinstance(r, dict): | |
| if r.get("tipo") == "email": | |
| emails.append(r.get("valor", "")) | |
| elif r.get("tipo") == "telefono": | |
| phones.append(r.get("valor", "")) | |
| return Contacto( | |
| emails=emails, | |
| telefonos=phones, | |
| redes_sociales=_safe_list(data, "redes_sociales"), | |
| ) | |
| def build_domicilios(data: dict) -> list[Domicilio]: | |
| """Construye lista de domicilios.""" | |
| domicilios_raw = _safe_list(data, "domicilios") | |
| domicilios = [] | |
| for d in domicilios_raw: | |
| if isinstance(d, dict): | |
| domicilios.append(Domicilio( | |
| calle=_safe_get(d, "calle"), | |
| numero=_safe_get(d, "numero"), | |
| piso=_safe_get(d, "piso"), | |
| depto=_safe_get(d, "depto"), | |
| localidad=_safe_get(d, "localidad"), | |
| provincia=_safe_get(d, "provincia"), | |
| codigo_postal=_safe_get(d, "codigo_postal"), | |
| tipo=_safe_get(d, "tipo"), | |
| )) | |
| return domicilios | |
| def build_datos_fiscales(arca_data: dict, cuit: str, actividades: list[ActividadFiscal] = None) -> DatosFiscales: | |
| """Construye datos fiscales desde ARCA/AFIP.""" | |
| if not isinstance(arca_data, dict): | |
| arca_data = {} | |
| domicilios = build_domicilios(arca_data) | |
| domicilio_fiscal_raw = _safe_get(arca_data, "domicilio_fiscal") | |
| domicilio_fiscal = Domicilio(**domicilio_fiscal_raw) if isinstance(domicilio_fiscal_raw, dict) and domicilio_fiscal_raw else None | |
| if domicilio_fiscal and not domicilios: | |
| domicilios = [domicilio_fiscal] | |
| monotributo_raw = _safe_get(arca_data, "monotributo") | |
| monotributo_obj = Monotributo(**monotributo_raw) if isinstance(monotributo_raw, dict) else None | |
| return DatosFiscales( | |
| cuit=arca_data.get("cuit", cuit), | |
| tipo_clave=_safe_get(arca_data, "tipo_clave"), | |
| tipo_documento=_safe_get(arca_data, "tipo_documento"), | |
| numero_documento=_safe_get(arca_data, "numero_documento"), | |
| nombres=_safe_get(arca_data, "nombres"), | |
| apellido=_safe_get(arca_data, "apellido"), | |
| nombres_completo=_safe_get(arca_data, "nombres_completo"), | |
| condicion_iva=_safe_get(arca_data, "condicion_iva"), | |
| estado_afip=_safe_get(arca_data, "estado_afip"), | |
| fecha_inicio_actividad=_safe_get(arca_data, "fecha_inicio_actividad"), | |
| fecha_nacimiento=_safe_get(arca_data, "fecha_nacimiento"), | |
| fecha_contrato_social=_safe_get(arca_data, "fecha_contrato_social"), | |
| fecha_fallecimiento=_safe_get(arca_data, "fecha_fallecimiento"), | |
| forma_juridica=_safe_get(arca_data, "forma_juridica"), | |
| mes_cierre=_safe_get(arca_data, "mes_cierre"), | |
| periodo_actividad_principal=_safe_get(arca_data, "periodo_actividad_principal"), | |
| actividades=actividades or [], | |
| domicilios=domicilios, | |
| domicilio_fiscal=domicilio_fiscal, | |
| monotributo=monotributo_obj, | |
| ) | |
| def build_datos_financieros(bcra_data: dict, historial_financiero_anterior: dict = None) -> DatosFinancieros: | |
| """Construye datos financieros desde BCRA + fallback histórico.""" | |
| if not isinstance(bcra_data, dict): | |
| bcra_data = {} | |
| deudas = [] | |
| for ent in _safe_list(bcra_data, "entidades"): | |
| if isinstance(ent, dict): | |
| deudas.append(BcraHistorial( | |
| entidad=ent.get("entidad"), | |
| situacion=ent.get("situacion"), | |
| fecha=ent.get("fecha"), | |
| monto=ent.get("monto"), | |
| tipo=ent.get("tipo"), | |
| )) | |
| cheques = [] | |
| for ch in _safe_list(bcra_data, "cheques_rechazados"): | |
| if isinstance(ch, dict): | |
| cheques.append(ChequeRechazado( | |
| fecha=ch.get("fecha"), | |
| banco=ch.get("banco"), | |
| sucursal=ch.get("sucursal"), | |
| monto=ch.get("monto"), | |
| motivo=ch.get("motivo"), | |
| )) | |
| # Fallback histórico si BCRA falló | |
| if not _safe_get(bcra_data, "entidades") and historial_financiero_anterior: | |
| hfa = historial_financiero_anterior | |
| situacion = hfa.get("bcra_situacion_actual") | |
| if situacion: | |
| bcra_data = { | |
| "bcra_situacion_actual": situacion, | |
| "entidades": hfa.get("entidades", []), | |
| "cheques_rechazados": hfa.get("cheques_rechazados", []), | |
| } | |
| situacion = _safe_get(bcra_data, "bcra_situacion_actual") | |
| if situacion is None: | |
| situacion = 1 # Normal por defecto | |
| return DatosFinancieros( | |
| bcra_situacion_actual=situacion, | |
| bcra_situacion_descripcion=SITUACIONES_BCRA.get(situacion, "Desconocida"), | |
| bcra_historial=_safe_list(bcra_data, "entidades"), | |
| bcra_total_deuda_miles=_safe_get(bcra_data, "bcra_total_deuda_miles", 0.0), | |
| bcra_dias_atraso_max=_safe_get(bcra_data, "bcra_dias_atraso_max", 0), | |
| cheques_rechazados=_safe_list(bcra_data, "cheques_rechazados"), | |
| tiene_deuda=_safe_get(bcra_data, "tiene_deuda", False), | |
| ) | |
| def build_datos_societarios(igj_data: dict, inpi_data: dict, compras_data: dict) -> DatosSocietarios: | |
| """Construye datos societarios.""" | |
| return DatosSocietarios( | |
| igj=_safe_dict(igj_data, "igj"), | |
| inpi=_safe_dict(inpi_data, "inpi"), | |
| compras_estatales=_safe_dict(compras_data, "compras_estatales"), | |
| ) | |
| def build_datos_patrimoniales( | |
| arba_auto_data: dict, arba_catastro_data: dict, | |
| dnrpa_data: dict, infracciones_data: dict, | |
| carto_arba_data: dict, sinais_data: dict | |
| ) -> DatosPatrimoniales: | |
| """Construye datos patrimoniales.""" | |
| inmuebles = [] | |
| for inm in _safe_list(arba_catastro_data, "inmuebles"): | |
| if isinstance(inm, dict): | |
| inmuebles.append(Inmueble( | |
| partida=inm.get("partida"), | |
| nomenclatura=inm.get("nomenclatura"), | |
| direccion=inm.get("direccion"), | |
| superficie=inm.get("superficie"), | |
| valuacion=inm.get("valuacion"), | |
| tipo=inm.get("tipo"), | |
| )) | |
| vehiculos = [] | |
| for v in _safe_list(dnrpa_data, "vehiculos"): | |
| if isinstance(v, dict): | |
| vehiculos.append(Vehiculo( | |
| dominio=v.get("dominio"), | |
| marca=v.get("marca"), | |
| modelo=v.get("modelo"), | |
| anio=v.get("anio"), | |
| tipo=v.get("tipo"), | |
| registro=v.get("registro"), | |
| titular=v.get("titular"), | |
| estado=v.get("estado"), | |
| )) | |
| infracciones = [] | |
| for inf in _safe_list(infracciones_data, "infracciones"): | |
| if isinstance(inf, dict): | |
| infracciones.append(InfraccionTransito( | |
| fecha=inf.get("fecha"), | |
| tipo=inf.get("tipo"), | |
| jurisdiccion=inf.get("jurisdiccion"), | |
| monto=inf.get("monto"), | |
| estado=inf.get("estado"), | |
| )) | |
| return DatosPatrimoniales( | |
| inmuebles=inmuebles, | |
| vehiculos=vehiculos, | |
| infracciones_transito=infracciones, | |
| ) | |
| def build_datos_judiciales( | |
| pj_data: dict, pj_prov_data: dict, | |
| bo_data: dict, bo_prov_data: dict, | |
| inhibiciones_data: dict, juba_data: dict, | |
| siscop_data: dict | |
| ) -> DatosJudiciales: | |
| """Construye datos judiciales.""" | |
| causas = [] | |
| for c in _safe_list(pj_data, "causas"): | |
| if isinstance(c, dict): | |
| causas.append(CausaJudicial( | |
| numero=c.get("numero"), | |
| fuero=c.get("fuero"), | |
| caratula=c.get("caratula"), | |
| estado=c.get("estado"), | |
| fecha=c.get("fecha"), | |
| rol=c.get("rol"), | |
| )) | |
| publicaciones = [] | |
| for p in _safe_list(bo_data, "publicaciones"): | |
| if isinstance(p, dict): | |
| publicaciones.append(PublicacionBO( | |
| fecha=p.get("fecha"), | |
| seccion=p.get("seccion"), | |
| texto=p.get("texto"), | |
| url=p.get("url"), | |
| )) | |
| inhibiciones = [] | |
| for inh in _safe_list(inhibiciones_data, "inhibiciones"): | |
| if isinstance(inh, dict): | |
| inhibiciones.append(Inhibicion( | |
| numero=inh.get("numero"), | |
| juzgado=inh.get("juzgado"), | |
| fecha=inh.get("fecha"), | |
| monto=inh.get("monto"), | |
| estado=inh.get("estado"), | |
| )) | |
| return DatosJudiciales( | |
| causas=causas, | |
| publicaciones_bo=publicaciones, | |
| inhibiciones=inhibiciones, | |
| ) | |
| def build_vinculos(igj_data: dict, domicilios: list[Domicilio]) -> list[Vinculo]: | |
| """Detecta vínculos por domicilio compartido (IGJ).""" | |
| vinculos = [] | |
| if not igj_data or not domicilios: | |
| return vinculos | |
| doms_persona = set() | |
| for d in domicilios: | |
| parts = [d.calle, d.numero, d.localidad] | |
| normalized = " ".join(p.lower().strip() for p in parts if p).strip() | |
| if normalized and len(normalized) > 5: | |
| doms_persona.add(normalized) | |
| for socio in igj_data.get("socios_directivos", []): | |
| if not isinstance(socio, dict): | |
| continue | |
| dom_socio = socio.get("domicilio", "") | |
| if dom_socio: | |
| dom_norm = " ".join(dom_socio.lower().split()[:5]) | |
| for dom_p in doms_persona: | |
| if dom_norm and dom_p and (dom_norm in dom_p or dom_p in dom_norm): | |
| vinculos.append(Vinculo( | |
| cuit=socio.get("cuil"), | |
| nombre=socio.get("nombre", ""), | |
| tipo="Domiciliario", | |
| detalle=f"Domicilio compartido: {dom_socio}" | |
| )) | |
| break | |
| return vinculos | |
| def build_riesgo_indicadores(data: dict, all_results: dict) -> list[IndicadorRiesgo]: | |
| """Construye indicadores de riesgo.""" | |
| indicadores = [] | |
| # BCRA | |
| financiero = _safe_dict(data, "financiero") | |
| situacion = financiero.get("bcra_situacion_actual") | |
| if situacion and situacion > 1: | |
| indicadores.append(IndicadorRiesgo( | |
| codigo="BCRA_SITUACION", | |
| nivel="Alto" if situacion >= 4 else "Medio", | |
| descripcion=f"Situación BCRA: {SITUACIONES_BCRA.get(situacion, 'Desconocida')}", | |
| detalle=f"Situación actual: {situacion}", | |
| )) | |
| # Judicial | |
| judicial = _safe_dict(data, "judicial") | |
| causas = _safe_list(judicial, "causas") | |
| if len(causas) > 3: | |
| indicadores.append(IndicadorRiesgo( | |
| codigo="JUDICIAL_CAUSAS_MULTIPLES", | |
| nivel="Medio", | |
| descripcion="Múltiples causas judiciales", | |
| detalle=f"Se detectaron {len(causas)} causas judiciales", | |
| )) | |
| # Inhibiciones | |
| inhibiciones = _safe_list(judicial, "inhibiciones") | |
| if inhibiciones: | |
| indicadores.append(IndicadorRiesgo( | |
| codigo="INHIBICIONES", | |
| nivel="Alto", | |
| descripcion="Inhibiciones registradas", | |
| detalle=f"{len(inhibiciones)} inhibición(es) activa(s)", | |
| )) | |
| # Deudores alimentarios | |
| deudores = _safe_list(data.get("deudores_alimentarios", {}), "deudores") | |
| if deudores: | |
| indicadores.append(IndicadorRiesgo( | |
| codigo="DEUDOR_ALIMENTARIO", | |
| nivel="Alto", | |
| descripcion="Registro de deudor alimentario moroso", | |
| detalle="Aparece en RDAM", | |
| )) | |
| # BCRA cheques rechazados | |
| cheques = _safe_list(financiero, "cheques_rechazados") | |
| if cheques: | |
| indicadores.append(IndicadorRiesgo( | |
| codigo="CHEQUES_RECHAZADOS", | |
| nivel="Medio", | |
| descripcion="Cheques rechazados registrados", | |
| detalle=f"{len(cheques)} cheque(s) rechazado(s)", | |
| )) | |
| return indicadores | |
| def build_person_report( | |
| cuit: str, | |
| data: dict, | |
| results: dict, | |
| force_refresh: bool = False, | |
| ) -> PersonReport: | |
| """Construye reporte completo de persona.""" | |
| # Datos base | |
| arca_data = _safe_dict(results.get("arca_afip", {}), "data") if "arca_afip" in results else _safe_dict(data, "fiscal") | |
| bcra_data = _safe_dict(results.get("bcra", {}), "data") if "bcra" in results else _safe_dict(data, "financiero") | |
| igj_data = _safe_dict(results.get("igj", {}), "data") if "igj" in results else _safe_dict(data, "societario", {}).get("igj", {}) | |
| inpi_data = _safe_dict(results.get("inpi", {}), "data") if "inpi" in results else _safe_dict(data, "societario", {}).get("inpi", {}) | |
| compras_data = _safe_dict(results.get("compras_estatales", {}), "data") if "compras_estatales" in results else _safe_dict(data, "societario", {}).get("compras_estatales", {}) | |
| # Identificación | |
| identificacion = build_identificacion(arca_data, cuit) | |
| contacto = build_contacto(_safe_dict(data, "contacto")) | |
| domicilios = build_domicilios(arca_data) | |
| # Secciones principales | |
| fiscal = build_datos_fiscales(arca_data, cuit) | |
| financiero = build_datos_financieros(bcra_data, _safe_dict(data, "financiero")) | |
| societario = build_datos_societarios(igj_data, inpi_data, compras_data) | |
| patrimonial = build_datos_patrimoniales( | |
| _safe_dict(data, "arba_automotores"), | |
| _safe_dict(data, "arba_catastro"), | |
| _safe_dict(data, "dnrpa"), | |
| _safe_dict(data, "infracciones"), | |
| _safe_dict(data, "carto_arba"), | |
| _safe_dict(data, "sinai"), | |
| ) | |
| judicial = build_datos_judiciales( | |
| _safe_dict(data, "poder_judicial"), | |
| _safe_dict(data, "poder_judicial_provincial"), | |
| _safe_dict(data, "boletin_oficial"), | |
| _safe_dict(data, "boletines_provinciales"), | |
| _safe_dict(data, "inhibiciones"), | |
| _safe_dict(data, "juba"), | |
| _safe_dict(data, "siscop"), | |
| ) | |
| previsional = DatosPrevisionales( | |
| anses=_safe_dict(data, "anses"), | |
| monotributo_historial=_safe_dict(data, "monotributo_historial"), | |
| ) | |
| academico = DatosAcademicos( | |
| sgarhu=_safe_dict(data, "sgarhu"), | |
| titulos=[], | |
| ) | |
| registro_civil = DatosRegistroCivil( | |
| siscop=_safe_dict(data, "siscop"), | |
| defunciones=[], | |
| ) | |
| billeteras = DatosBilleterasVirtuales( | |
| billeteras=_safe_list(data.get("billeteras_virtuales", {}), "billeteras"), | |
| ) | |
| compras_estatales = ContratoEstado(**_safe_dict(data, "compras_estatales")) if data.get("compras_estatales") else None | |
| # Marcas INPI | |
| marcas_inpi = [] | |
| for m in _safe_list(inpi_data, "marcas"): | |
| if isinstance(m, dict): | |
| marcas_inpi.append(MarcaINPI( | |
| numero=m.get("numero"), | |
| denominacion=m.get("denominacion"), | |
| clase=m.get("clase"), | |
| estado=m.get("estado"), | |
| titular=m.get("titular"), | |
| fecha_presentacion=m.get("fecha_presentacion"), | |
| )) | |
| # Vínculos | |
| domicilios_objs = [Domicilio(**d) if isinstance(d, dict) else d for d in _safe_list(arca_data, "domicilios")] | |
| vinculos = build_vinculos(igj_data, domicilios_objs) | |
| # Riesgo | |
| riesgo = build_riesgo_indicadores(data, _safe_dict(data, "resultados")) | |
| # Timeline BO | |
| timeline = [] | |
| for t in _safe_list(data.get("timeline_boa", {}), "eventos"): | |
| if isinstance(t, dict): | |
| timeline.append(TimelineEvent( | |
| fecha=t.get("fecha"), | |
| tipo=t.get("tipo"), | |
| descripcion=t.get("descripcion"), | |
| fuente=t.get("fuente"), | |
| )) | |
| # Deudores alimentarios | |
| deudores = [] | |
| for d in _safe_list(data.get("deudores_alimentarios", {}), "deudores"): | |
| if isinstance(d, dict): | |
| deudores.append(DeudorAlimentario( | |
| dni=d.get("dni"), | |
| nombre=d.get("nombre"), | |
| estado=d.get("estado"), | |
| detalle=d.get("detalle"), | |
| )) | |
| # Monotributo historial | |
| monotributo = None | |
| mh = _safe_dict(data, "monotributo_historial") | |
| if mh: | |
| monotributo = Monotributo( | |
| historial_categorias=_safe_list(mh, "historial_categorias"), | |
| categoria_actual=mh.get("categoria_actual"), | |
| es_monotributista=mh.get("es_monotributista", False), | |
| nota=mh.get("nota"), | |
| ) | |
| # Registro conductores | |
| licencia = None | |
| rc = _safe_dict(data, "registro_conductores") | |
| if rc: | |
| licencia = { | |
| "numero": rc.get("numero"), | |
| "categoria": rc.get("categoria"), | |
| "vencimiento": rc.get("vencimiento"), | |
| } | |
| # Score | |
| score = compute_score(PersonReport( | |
| meta=ReportMeta(report_id="", generated_at=datetime.now(timezone.utc), sources=[]), | |
| identificacion=identificacion, | |
| contacto=contacto, | |
| domicilios=domicilios, | |
| fiscal=fiscal, | |
| financiero=financiero, | |
| societario=societario, | |
| patrimonial=patrimonial, | |
| judicial=judicial, | |
| previsional=previsional, | |
| academico=academico, | |
| registro_civil=registro_civil, | |
| billeteras_virtuales=billeteras, | |
| compras_estatales=compras_estatales, | |
| marcas_inpi=marcas_inpi, | |
| timeline=timeline, | |
| deudores_alimentarios=deudores, | |
| monotributo_historial=monotributo, | |
| licencia_conducir=licencia, | |
| vinculos=[], | |
| riesgo=riesgo, | |
| )) | |
| return PersonReport( | |
| meta=ReportMeta( | |
| report_id=uuid.uuid4().hex[:12], | |
| generated_at=datetime.now(timezone.utc), | |
| sources=[s for s in ["arca_afip", "bcra", "igj", "inpi", "bcra", "dnrpa", "poder_judicial", | |
| "renaper", "anses", "cnv", "uif", "boletin_oficial", "boletines_provinciales", | |
| "anses", "sinai", "inpi", "juba", "inhibiciones", "poder_judicial_provincial", | |
| "siscop", "billeteras_virtuales", "ruido", "sgarhu", "contratar", | |
| "colegios_profesionales", "renaper_facial", "archive_org", "padron_electoral", | |
| "compras_estatales", "cnv"] if s in results], | |
| ), | |
| score=score, | |
| identificacion=identificacion, | |
| contacto=contacto, | |
| domicilios=domicilios, | |
| fiscal=fiscal, | |
| financiero=financiero, | |
| societario=societario, | |
| patrimonial=patrimonial, | |
| judicial=judicial, | |
| previsional=previsional, | |
| academico=academico, | |
| registro_civil=registro_civil, | |
| billeteras_virtuales=billeteras, | |
| compras_estatales=compras_estatales, | |
| marcas_inpi=marcas_inpi, | |
| timeline=timeline, | |
| deudores_alimentarios=deudores, | |
| monotributo_historial=monotributo, | |
| registro_conductores=licencia, | |
| vinculos=vinculos, | |
| riesgo=riesgo, | |
| ) | |
| def build_company_report(cuit: str, data: dict, results: dict) -> CompanyReport: | |
| """Construye reporte de empresa.""" | |
| # Similar a build_person_report pero para empresa | |
| # ... implementación simplificada | |
| return CompanyReport( | |
| meta=ReportMeta(report_id=uuid.uuid4().hex[:12], generated_at=datetime.now(timezone.utc), sources=[]), | |
| score=compute_company_score(CompanyReport( | |
| meta=ReportMeta(report_id="", generated_at=datetime.now(timezone.utc), sources=[]), | |
| identificacion=CompanyIdentificacion(cuit=cuit, razon_social=""), | |
| fiscal=DatosFiscales(cuit=cuit), | |
| financiero=DatosFinancieros(bcra_situacion_actual=1, bcra_situacion_descripcion="Normal"), | |
| societario=DatosSocietarios(), | |
| judicial=DatosJudiciales(), | |
| patrimonial=DatosPatrimoniales(), | |
| billeteras_virtuales=DatosBilleterasVirtuales(), | |
| riesgo=[], | |
| )), | |
| identificacion=CompanyIdentificacion(cuit=cuit, razon_social=""), | |
| fiscal=DatosFiscales(cuit=cuit), | |
| financiero=DatosFinancieros(bcra_situacion_actual=1, bcra_situacion_descripcion="Normal"), | |
| societario=DatosSocietarios(), | |
| judicial=DatosJudiciales(), | |
| patrimonial=DatosPatrimoniales(), | |
| billeteras_virtuales=DatosBilleterasVirtuales(), | |
| riesgo=[], | |
| ) | |
| def build_vehicle_report(dominio: str, data: dict, results: dict) -> VehicleReport: | |
| """Construye reporte de vehículo.""" | |
| dnrpa = _safe_dict(data, "dnrpa") | |
| infracciones = _safe_dict(data, "infracciones") | |
| siniestros = _safe_dict(data, "siniestros") | |
| sinais = _safe_dict(data, "sinais") | |
| vehiculo = None | |
| for v in _safe_list(dnrpa, "vehiculos"): | |
| if isinstance(v, dict) and v.get("dominio") == dominio: | |
| vehiculo = Vehiculo( | |
| dominio=v.get("dominio"), | |
| marca=v.get("marca"), | |
| modelo=v.get("modelo"), | |
| anio=v.get("anio"), | |
| tipo=v.get("tipo"), | |
| registro=v.get("registro"), | |
| titular=v.get("titular"), | |
| estado=v.get("estado"), | |
| ) | |
| break | |
| infracciones_list = [] | |
| for inf in _safe_list(infracciones, "infracciones"): | |
| if isinstance(inf, dict): | |
| infracciones_list.append(InfraccionTransito( | |
| fecha=inf.get("fecha"), | |
| tipo=inf.get("tipo"), | |
| jurisdiccion=inf.get("jurisdiccion"), | |
| monto=inf.get("monto"), | |
| estado=inf.get("estado"), | |
| )) | |
| return VehicleReport( | |
| meta=ReportMeta(report_id=uuid.uuid4().hex[:12], generated_at=datetime.now(timezone.utc), sources=list(results.keys())), | |
| vehiculo=vehiculo, | |
| infracciones=infracciones_list, | |
| siniestros=[], | |
| riesgo=[], | |
| ) | |
| def build_property_report(calle: str, numero: str, localidad: str, provincia: str, data: dict, results: dict) -> PropertyReport: | |
| """Construye reporte de propiedad.""" | |
| arba_catastro = _safe_dict(data, "arba_catastro") | |
| carto_arba = _safe_dict(data, "carto_arba") | |
| bo_data = _safe_dict(data, "boletin_oficial") | |
| bo_prov = _safe_dict(data, "boletin_oficial_pba") | |
| inmuebles = [] | |
| for inm in _safe_list(arba_catastro, "inmuebles"): | |
| if isinstance(inm, dict): | |
| inmuebles.append(Inmueble( | |
| partida=inm.get("partida"), | |
| nomenclatura=inm.get("nomenclatura"), | |
| direccion=inm.get("direccion"), | |
| superficie=inm.get("superficie"), | |
| valuacion=inm.get("valuacion"), | |
| tipo=inm.get("tipo"), | |
| )) | |
| return PropertyReport( | |
| meta=ReportMeta(report_id=uuid.uuid4().hex[:12], generated_at=datetime.now(timezone.utc), sources=list(results.keys())), | |
| direccion=f"{calle} {numero}, {localidad}, {provincia}", | |
| inmuebles=inmuebles, | |
| publicaciones_bo=[], | |
| riesgo=[], | |
| ) | |
| def build_group_report(cuit: str, data: dict, results: dict) -> GroupReport: | |
| """Construye reporte de grupo económico.""" | |
| persona = build_person_report(cuit, data, results) | |
| # TODO: Empresas vinculadas, vehículos, inmuebles | |
| return GroupReport( | |
| meta=ReportMeta(report_id=uuid.uuid4().hex[:12], generated_at=datetime.now(timezone.utc), sources=list(results.keys())), | |
| score_grupo=compute_group_score(PersonReport(...), [], [], []), # Simplificado | |
| persona=persona, | |
| empresas=[], | |
| vehiculos=[], | |
| inmuebles=[], | |
| ) |