""" deshacer_btc.py — Volver a empezar el bitcoin: quita lo que metieron el CSV de un extracto de exchanges y el historial de los monederos, sin tocar nada más. Qué se quita: • las operaciones que creó el CSV de exchanges (su línea empieza por «ct:»); • todo lo que guardaste desde el nodo, sea revisando todo el historial o en la comprobación diaria (cada importación se deshace entera: lo creado se borra y a lo enlazado se le quita el txid); • las decisiones sin guardar (borradores) y lo recordado de cada exchange; • los activos «BTC en …» que creó el CSV, si se quedan sin operaciones. Qué se queda: los monederos, lo que tenías apuntado antes (aunque el historial lo hubiera enlazado) y cualquier operación hecha a mano. Se borra marcando, como todo en la app, así que la sincronización lo lleva también a la copia de tu servidor git. Primero se simula (qué y cuánto) y solo se aplica si se confirma. """ from __future__ import annotations from . import historial_btc PREFIJOS_CSV = ("ct:", "ct-fee:") def _del_csv(m: dict) -> bool: return str(m.get("extracto") or "").startswith(PREFIJOS_CSV) def plan(cartera, config_btc: dict) -> dict: """Lo que se quitaría, sin tocar nada.""" movs = cartera.datos.vivos("movimientos") todos = cartera.datos.movimientos imps = config_btc.get("importaciones") or [] vivos = {m["id"] for m in movs} creados_hist = {i for imp in imps for i in imp.get("creados") or [] if i in vivos} enlazados = {i for imp in imps for i in imp.get("enlazados") or [] if i in vivos} del_csv = {m["id"] for m in movs if _del_csv(m)} quitar = del_csv | creados_hist # Activos que creó el CSV: tienen (o tuvieron) alguna operación suya y no # les queda ninguna que no se vaya a quitar con_csv = {m["activo"] for m in todos if _del_csv(m)} activos, se_quedan = [], [] for a in cartera.datos.vivos("activos"): if a["id"] not in con_csv: continue restantes = [m for m in movs if m["activo"] == a["id"] and m["id"] not in quitar] if restantes: se_quedan.append({"id": a["id"], "nombre": a["nombre"], "operaciones": len(restantes)}) else: activos.append({"id": a["id"], "nombre": a["nombre"]}) en_uso = {m.get("activo") for m in config_btc.get("monederos") or []} for a in list(activos): if a["id"] in en_uso: # un monedero apunta ahí: no se borra activos.remove(a) se_quedan.append({**a, "operaciones": 0, "monedero": True}) return {"del_csv": len(del_csv), "del_historial": len(creados_hist - del_csv), "desenlazar": len(enlazados - quitar), "importaciones": len(imps), "decisiones": len(config_btc.get("resueltas") or {}), "borradores": len(config_btc.get("borradores") or {}), "activos": activos, "activos_que_se_quedan": se_quedan} def aplicar(cartera, config_btc: dict, ajustes_extractos: dict) -> dict: """Quita lo del plan. Cambia config_btc y ajustes_extractos en el sitio; quien llama los guarda.""" p = plan(cartera, config_btc) # 1. El historial, importación a importación (borra lo creado, quita enlaces) for imp in list(config_btc.get("importaciones") or []): historial_btc.deshacer(cartera, config_btc, imp["id"]) config_btc["resueltas"] = {} config_btc["borradores"] = {} config_btc["importaciones"] = [] # 2. Lo que metió el CSV ids = [m["id"] for m in cartera.datos.vivos("movimientos") if _del_csv(m)] if ids: cartera.borrar_movimientos(ids) # 3. Los activos «BTC en …» que se han quedado vacíos if p["activos"]: cartera.borrar_activos_vacios([a["id"] for a in p["activos"]]) ajustes_extractos.pop("destinos_exchange", None) return p