From 53fbf19a0b2efc108445ae2d8d21fca933d89cf8 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 30 Jun 2026 14:57:36 +0200 Subject: [PATCH] Fix montants (locale) + timeout fetch Indy + message d'erreur --- compta/__pycache__/indy.cpython-310.pyc | Bin 0 -> 5084 bytes .../__pycache__/views_import.cpython-310.pyc | Bin 0 -> 14630 bytes compta/indy.py | 18 ++++- compta/templates/compta/import_csv.html | 6 +- compta/views_bookmarklet.py | 8 ++ entrypoint.sh | 2 +- indy-mcp/bookmarklet.html | 56 ++++++++++++++ indy-mcp/bookmarklet.js | 69 ++++++++++++++++++ 8 files changed, 152 insertions(+), 7 deletions(-) create mode 100644 compta/__pycache__/indy.cpython-310.pyc create mode 100644 compta/__pycache__/views_import.cpython-310.pyc create mode 100644 compta/views_bookmarklet.py create mode 100644 indy-mcp/bookmarklet.html create mode 100644 indy-mcp/bookmarklet.js diff --git a/compta/__pycache__/indy.cpython-310.pyc b/compta/__pycache__/indy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d403d9c26bcdb0329dceebe41038b1da32c30d90 GIT binary patch literal 5084 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 UE. -⚠️ API non officielle d'Indy : pour les données de l'utilisateur. Le token JWT +API non officielle d'Indy : pour les données de l'utilisateur. Le token JWT expire (~1 h) et doit être renouvelé. """ from decimal import Decimal @@ -96,14 +96,26 @@ def fetch_transactions(token, date_debut=None, date_fin=None, search="", page=1, params["dateFrom"] = date_debut if date_fin: params["dateTo"] = date_fin + timeout = httpx.Timeout(12.0, connect=8.0) try: with httpx.Client(base_url=base_url.rstrip("/"), headers=headers, - timeout=30, follow_redirects=True) as c: + timeout=timeout, follow_redirects=True) as c: r = c.get(TRANSACTIONS_PATH, params=params) if r.status_code != 200: - return r.status_code, [], f"HTTP {r.status_code} (token expiré ?)" + return r.status_code, [], ( + f"HTTP {r.status_code} — token expire, ou requete bloquee par " + f"Cloudflare depuis le serveur.") + if "json" not in r.headers.get("content-type", "").lower(): + return r.status_code, [], ( + "Reponse non-JSON (probablement Cloudflare). Le conteneur n'arrive " + "pas a joindre Indy directement. Recupere le CSV depuis ton poste " + "(MCP/CLI) et colle-le ci-dessous.") data = r.json() return 200, data.get("transactions", []), None + except httpx.TimeoutException: + return None, [], ("Delai depasse en joignant Indy : le conteneur n'a peut-etre " + "pas d'acces Internet, ou Cloudflare bloque. Utilise le CSV " + "depuis ton poste.") except Exception as ex: # noqa: BLE001 return None, [], f"{type(ex).__name__}: {ex}" diff --git a/compta/templates/compta/import_csv.html b/compta/templates/compta/import_csv.html index 33b7ea3..8bf24fe 100644 --- a/compta/templates/compta/import_csv.html +++ b/compta/templates/compta/import_csv.html @@ -1,4 +1,4 @@ - +{% load l10n %} @@ -128,8 +128,8 @@ {% for val,lab in regimes %}{% endfor %} - - + + {{ l.type }} diff --git a/compta/views_bookmarklet.py b/compta/views_bookmarklet.py new file mode 100644 index 0000000..14f969f --- /dev/null +++ b/compta/views_bookmarklet.py @@ -0,0 +1,8 @@ +"""Page d'installation du favori « Indy → CSV ».""" +from django.contrib.auth.decorators import login_required +from django.shortcuts import render + + +@login_required +def bookmarklet(request): + return render(request, "compta/bookmarklet.html", {}) diff --git a/entrypoint.sh b/entrypoint.sh index dbc19e5..6ad933e 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -20,4 +20,4 @@ if [ "$SEED_DEMO" = "1" ]; then fi echo "→ Démarrage de Gunicorn sur :8000" -exec gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 3 +exec gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 3 --timeout 60 diff --git a/indy-mcp/bookmarklet.html b/indy-mcp/bookmarklet.html new file mode 100644 index 0000000..f2ebd13 --- /dev/null +++ b/indy-mcp/bookmarklet.html @@ -0,0 +1,56 @@ + + + + + +Indy → CSV — Favori + + + +

Favori « Indy → CSV »

+

Un clic sur la page Indy → tes transactions sont copiées au format CSV, + prêtes à coller dans JB Compta. Pas de token à chercher, la 2FA est déjà passée, + et tout se fait dans ton navigateur (donc pas de souci d'accès serveur).

+ +

Installation (30 s)

+
    +
  1. Affiche ta barre de favoris (Ctrl+Maj+B dans Chrome).
  2. +
  3. Glisse-dépose ce bouton dans la barre de favoris : +   Indy → CSV
  4. +
  5. Va sur app.indy.fr (connecté), puis clique le favori.
  6. +
  7. Saisis la période → le CSV est copié → colle-le dans /import/ de JB Compta.
  8. +
+ +
Si le glisser-déposer ne marche pas : crée un favori manuellement, + puis colle le code ci-dessous comme URL du favori.
+ +

Code (installation manuelle)

+ + +

Notes

+
    +
  • À utiliser uniquement quand l'onglet actif est app.indy.fr.
  • +
  • Aucun secret n'est stocké : le favori lit ta session en cours.
  • +
  • Si une alerte « Erreur Indy » apparaît, reconnecte-toi à Indy et réessaie.
  • +
  • Le mapping des catégories (compte comptable → catégorie) est le même que dans l'app.
  • +
+ + + + diff --git a/indy-mcp/bookmarklet.js b/indy-mcp/bookmarklet.js new file mode 100644 index 0000000..b229020 --- /dev/null +++ b/indy-mcp/bookmarklet.js @@ -0,0 +1,69 @@ +/* + * Bookmarklet « Indy → CSV » — version lisible (documentation). + * Le bouton prêt à installer est dans bookmarklet.html. + * + * Usage : être connecté sur app.indy.fr, cliquer le favori. Il demande une + * période, récupère les transactions (dans TON navigateur = autorisé, 2FA déjà + * passée, pas de problème Cloudflare ni d'accès serveur), construit le CSV au + * format JB Compta et le copie dans le presse-papier. Tu le colles dans /import/. + */ +(async () => { + const CC = [ + ["701", "Vente de produits finis"], ["707", "Vente de produits finis"], + ["706", "Prestation de services"], + ["605", "Matériel et outillage"], ["606", "Matériel et outillage"], ["607", "Matériel et outillage"], + ["6256", "Frais de repas hors domicile"], ["6253", "Frais de repas hors domicile"], + ["626", "Télécom, fournitures, documentation"], + ["6181", "Télécom, fournitures, documentation"], ["6183", "Télécom, fournitures, documentation"], + ["6136", "Abonnement logiciel"], ["6226", "Abonnement logiciel"], + ["646", "Cotisation sociale Urssaf"], + ["44551", "TVA payée"], ["44558", "TVA payée"], ["44583", "Remboursement de TVA"], + ["108", "Prélèvement personnel"], + ]; + const CA = [["701", "vente"], ["707", "vente"], ["706", "service_bic"]]; + const cat = (n) => { n = String(n || ""); let b = null; for (const [p, c] of CC) { if (n.startsWith(p) && (!b || p.length > b[0].length)) b = [p, c]; } return b ? b[1] : ""; }; + const act = (n) => { n = String(n || ""); for (const [p, a] of CA) { if (n.startsWith(p)) return a; } return ""; }; + const norm = (tx) => { + const c = tx.totalAmountInCents; if (c == null) return null; + const mt = (c / 100).toFixed(2); + const ss = (tx.subdivisions || []).filter(s => !String((s.accounting_account || {}).number || "").startsWith("512")); + if (!ss.length) return null; + let m = ss[0]; for (const s of ss) if (Math.abs(s.amount_in_cents || 0) > Math.abs(m.amount_in_cents || 0)) m = s; + const num = String((m.accounting_account || {}).number || ""); + let rg = "", tx2 = 0; + if (m.tva_intracom && m.tva_intracom.type === "eu") { rg = "intracom"; tx2 = (m.tva_intracom.rate || 0) / 100; } + else { tx2 = (m.tva_rate || 0) / 100; } + const lib = (tx.description || tx.raw_description || "").replace(/;/g, " "); + return [tx.date || "", lib, cat(num), act(num), String(tx2), rg, mt].join(";"); + }; + const getTok = () => new Promise(r => { + const o = indexedDB.open("firebaseLocalStorageDb"); + o.onsuccess = () => { try { + const q = o.result.transaction("firebaseLocalStorage", "readonly").objectStore("firebaseLocalStorage").getAll(); + q.onsuccess = () => { const v = (q.result || []).map(x => x.value).find(v => v && v.stsTokenManager && v.stsTokenManager.accessToken); r(v ? v.stsTokenManager.accessToken : null); }; + q.onerror = () => r(null); + } catch (e) { r(null); } }; + o.onerror = () => r(null); + }); + const d1 = prompt("Date début (AAAA-MM-JJ)"); if (!d1) return; + const d2 = prompt("Date fin (AAAA-MM-JJ)"); if (!d2) return; + const tk = await getTok(); + const H = { "Accept": "application/json", "x-client-app-type": "web" }; + if (tk) H["Authorization"] = "Bearer " + tk; + let all = [], pg = 1, tot = 1e9; + try { + while (all.length < tot) { + const u = "/api/transactions/transactions-list?" + new URLSearchParams({ search: "", dateFrom: d1, dateTo: d2, page: pg }); + const r = await fetch(u, { headers: H, credentials: "include" }); + if (!r.ok) throw new Error("HTTP " + r.status); + const j = await r.json(); + tot = j.nbTransactions != null ? j.nbTransactions : (j.transactions || []).length; + const t = j.transactions || []; if (!t.length) break; + all = all.concat(t); pg++; if (pg > 60) break; + } + } catch (e) { alert("Erreur Indy : " + e.message + "\nEs-tu bien connecté sur app.indy.fr ?"); return; } + const rows = all.map(norm).filter(Boolean); + const csv = "date;libelle;categorie;activite;taux_tva;regime;montant\n" + rows.join("\n"); + try { await navigator.clipboard.writeText(csv); alert(rows.length + " opérations -> CSV copié ! Colle-le dans JB Compta (/import/)."); } + catch (e) { window.prompt("Copie ce CSV (Ctrl+C) :", csv); } +})();