Commit Graph

32 Commits

Author SHA1 Message Date
ac63922896 style: nomme partout les recettes et les depenses
All checks were successful
Build and Publish Docker Image / Build App Image (push) Successful in 22s
Build and Publish Docker Image / Build Summary (push) Successful in 3s
Les raccourcis de l'accueil parlaient de recettes quand la barre de
navigation disait « Revenus », et la page atteinte s'intitulait « Dashboard
Revenus Locatifs » : trois mots pour la meme chose sur un meme parcours.

Les libelles visibles suivent maintenant un seul vocabulaire, accents
compris. Les URL gardent leurs noms d'origine (/revenus, /analytics) :
elles peuvent figurer dans des signets, et un libelle n'a pas besoin de
coincider avec son adresse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:55:39 +02:00
9c2d4f7f82 feat: resume l'annee civile sur l'accueil
L'accueil ne decrivait qu'un document : les quatre tuiles lisaient le
dernier compte rendu importe, sans rien dire de ce que contient la base.

Il resume desormais une annee civile, avec un selecteur des annees
presentes. L'annee par defaut est celle du dernier compte rendu et non
l'annee en cours : la fenetre etait calee sur `date.today()`, si bien que
sans import depuis quelques mois l'ecran se serait vide alors que la base
est pleine.

Ce que les tuiles annoncent :

- recettes facturees, report exclu, avec l'encaisse et le recouvrement ;
- depenses, debit et credits recus ;
- net reverse, rapproche des soldes annonces par les comptes rendus ;
- restant du, date, car un stock ne se cumule pas d'un mois sur l'autre.

Le net reverse vaut « encaisse - debit + credit », et cette egalite tombe
au centime sur le solde extrait du PDF pour avril, mai et juin 2026. Elle
s'ecarte de 288,52 EUR en fevrier et de 1 188,03 EUR en mars, les deux mois
dont l'extraction a par ailleurs des defauts. L'ecart est donc affiche et
jamais lisse : c'est le seul controle de bout en bout dont on dispose sur
la qualite d'une extraction. Les regles vivent dans services/tresorerie.py,
a cote de celles des revenus.

Le lot compte est celui qui a ete facture dans l'annee : la table `lots`
retient deux ecritures par lot (« 0001 » et « 01 »), sequelle de la
normalisation des numeros, et en annoncerait 40 la ou il y en a 20.

Le graphique passe du vert et rouge au bleu et ambre : sous deuteranopie,
green-400 et red-400 ne se separent qu'a un delta E de 7,9, sous le seuil
de 8. La paire retenue tient a 30,2.

`/recent-revenus` disparait — c'etait le dernier agregat a compter les
lignes de report — et `/immeubles-shortcuts` est borne a la meme annee que
le reste de l'ecran, deux perimetres sur un ecran donnant deux montants
sans que rien ne les distingue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:52:10 +02:00
424abbaf07 feat: mene les actions rapides aux pages recettes et depenses
Les quatre raccourcis de l'accueil renvoyaient mal. « Importer un PDF »
repetait la zone de depot situee juste au-dessus. « Analyses » et
« Immeubles » ne disaient pas ce qu'on y trouve — des recettes et des
depenses. « Documents » ne menait pas a la page mais faisait defiler la
page d'accueil jusqu'a sa propre section, sans quitter l'ecran.

Trois destinations restent, nommees par ce qu'elles contiennent, et
chacune est un lien vers sa page. Le bleu et l'ambre sont ceux du
graphique mensuel : une couleur garde le meme sens d'un bout a l'autre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:52:10 +02:00
eb7eead555 feat: masque la section IA derriere un interrupteur de fonctionnalite
La section IA n'est pas prete a etre utilisee. Plutot que de supprimer le
code, deux interrupteurs alignes la retirent de l'application :

- frontend/src/features.js : onglet de navigation, page /ia (redirigee vers
  l'accueil pour ne pas casser un signet) et section « Configuration LLM »
  de la page Config. La page n'est plus embarquee dans le bundle.
- src/plesna_gerance/features.py : les routes /api/ia ne sont plus montees,
  les endpoints n'existent donc pas du tout.

Les settings Ollama restent en base : repasser les deux interrupteurs a
true suffit a tout reactiver, sans ressaisie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 12:14:27 +02:00
49e060e6e4 refactor: supprime le code mort et unifie les routes de tags
Code sans aucun appelant, retiré : DatabaseService.get_revenus_summary
(annoté list[dict] alors qu'il retournait un dict), get_depenses_summary,
get_tag_by_id et storage.file_exists.

Les tags étaient gérés à deux adresses : /api/tags (lecture, appelée par
trois composants) et /api/config/tags (lecture, création, renommage,
appelée par la seule page de configuration). Tout est regroupé sur
/api/tags, dans le module qui leur est dédié ; config.py ne garde que les
settings et ConfigPage est recâblée. Ces routes n'avaient aucun test :
sept en couvrent maintenant la création, le renommage, l'unicité et les
noms vides.

/api/stats disparaît également : sous-ensemble de /api/dashboard/stats,
il n'était appelé par personne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 09:44:28 +02:00
41107c984c style: aligne le balayage de re-extraction sur le design system
All checks were successful
Build and Publish Docker Image / Build App Image (push) Successful in 1m16s
Build and Publish Docker Image / Build Summary (push) Successful in 3s
La page et le panneau de differences avaient ete ecrits avant que main ne pose
un design system unique : classes Tailwind brutes, et surtout un detail
depliable reste sur fond clair alors que son contenu venait de passer en sombre.

Reprend les classes du systeme (page, card, table, btn, badge, subcard,
empty-state, spinner) et ramene le detail au fond sombre. Les avertissements de
reecriture passent en amber-400, illisibles jusqu'ici sur fond sombre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 07:09:46 +02:00
92cf21309f feat: affiche la date de derniere extraction et revient aux documents
La liste des documents montrait la date d'import, figee au premier
enregistrement : c'est la date de la derniere extraction ayant produit les
donnees affichees qui renseigne, surtout apres un balayage de re-extraction. La
colonne `extracted_at` la porte, mise a jour a chaque enregistrement, et la date
d'import reste consultable en infobulle.

Le projet n'ayant pas d'outil de migration (`create_all` laisse intactes les
tables existantes), `init_db` rattrape les colonnes ajoutees apres coup : sans
cela une base deja installee cesserait de fonctionner. Les documents deja
presents recoivent leur date d'import, qui est bien celle de leur extraction.

Une fois la selection appliquee sans echec, le balayage renvoie vers la liste des
documents ; en cas d'echec on reste sur place, les lignes concernees portant leur
message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 07:02:28 +02:00
a1da4fc97f feat: annonce les reecritures que l'enregistrement imposera
Refuser une modification, c'est reenvoyer la valeur actuelle du document. Mais
l'enregistrement ramene les donnees a une forme canonique (aujourd'hui les
numeros de lot) : sur ces champs, le refus n'est pas conserve. L'interface le
laissait croire.

Plutot que de traiter le cas des lots en dur, le serveur devient seul juge de ce
qu'il stocke et l'annonce : `canonicalize_extraction` regroupe les reecritures
faites a la persistance, `save_document` et l'apercu passent par elle, et
/api/documents/{id}/re-extract renvoie `previous_canonical` a cote de
`previous_data`. Le front compare ces deux jeux et signale, sous chaque case
decochee, la valeur que l'enregistrement reecrira — sans connaitre aucune regle.
Une transformation ajoutee plus tard remontera donc toute seule dans l'interface.

Toutes les differences restent visibles et toutes les cases actives : voir ce
qui change et pouvoir se prononcer prime, quitte a etre prevenu que ce champ-la
reviendra reecrit.

Supprime au passage frontend/src/utils/lots.js, qui dupliquait la regle de
normalisation cote client.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 07:02:01 +02:00
43efea4945 feat: valide la re-extraction modification par modification
Le balayage n'imposait que le tout ou rien par document. Chaque modification a
desormais sa case : un champ de metadonnee, le nom ou le type d'un locataire,
une operation ajoutee ou supprimee. Les champs textuels retenus sont en outre
modifiables a la main, pour les cas ou ni l'ancienne ni la nouvelle valeur ne
convient. Tout reste coche par defaut : le cas courant tient toujours en un clic.

Les montants et lignes d'un locataire forment un seul bloc : les retenir
separement produirait un total ne correspondant plus a ses lignes, alors que ces
chiffres alimentent les revenus et les depenses.

Le document enregistre est construit par fusion (mergeExtraction) : on part des
donnees en base et on n'y applique que ce qui est retenu. Le diff porte donc
maintenant de quoi rejouer chaque changement (identifiant, chemin, valeurs
brutes) et l'index d'origine des operations supprimees, pour les remettre a leur
place si on refuse leur disparition. Les tags suivent la liste d'operations
finale, y compris ceux d'une operation restauree.

Une reecriture de forme d'un numero de lot ("0001" -> "01") est signalee comme
imposee et sa case verrouillee : le backend normalise tout enregistrement, une
case sans effet aurait laisse croire l'inverse.

Ajoute vitest : la fusion decide de ce qui est ecrit en base, elle est couverte
par 15 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 07:02:01 +02:00
5f3a26e7d7 feat: balayage de re-extraction de toute la base
Nouvelle page /re-extraction, accessible depuis la liste des documents : elle
rejoue l'extraction de chaque PDF stocke, document par document, avec une
progression et une estimation du temps restant (une extraction prend plusieurs
secondes) et un bouton d'arret. Rien n'est ecrit en base pendant le balayage.

Les documents dont l'extraction change sont listes avec le nombre de
differences par section, deja coches ; les inchanges sont replies et les
documents sans PDF ou en erreur isoles. Le detail depliable reutilise
l'affichage de diff de la re-extraction unitaire (extrait dans
ExtractionDiffDetails). Un seul bouton enregistre toute la selection.

Les tags de depenses sont reportes par signature d'operation et non par index :
une operation ajoutee ou retiree par le nouveau parser ne decale plus les
categories. Ce qui n'est pas reapparie recoit une prediction, modifiable dans le
detail avant enregistrement.

L'edition d'un document et l'application du balayage passent par
PUT /api/documents/{id}, qui vise le document par son ID.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 07:01:01 +02:00
50508c98a8 chore(ui): supprime PdfUploader, composant mort
Aucun import ne le referencait : le televersement se fait depuis la zone
de depot de l'accueil et le bouton de l'en-tete.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 05:17:43 +02:00
7a87958af7 fix(ui): affiche les soldes crediteurs en vert
La comparaison portait sur « crediteur » sans accent alors que le parser
ecrit « créditeur » des qu'il a lu la mention dans le PDF : aucun solde
ne passait le test, tous s'affichaient en rouge.

Compare desormais sur une forme normalisee (sans accents ni casse), ce
qui couvre les deux formes presentes en base sans avoir a migrer les
documents deja extraits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 05:17:11 +02:00
14b39efe3b refactor(ui): aligne les composants de donnees sur le design system
Cartes, en-tetes, champs de filtre, tableaux, badges, paginations et
indicateurs de chargement des tableaux de bord etaient proches mais
jamais identiques (bordure presente ou absente, paddings et arrondis
variables). Ils utilisent maintenant les classes communes.

Les colonnes tronquees des tableaux sont elargies et les sept filtres
des depenses tiennent sur une ligne, la largeur retrouvee le permettant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:50:26 +02:00
02a3459291 refactor(ui): bascule le flux extraction/edition en theme sombre
Tout ce flux (visionneuse de donnees, fiches locataire et operation,
tagging, autocompletion, panneau de differences) etait en theme clair,
au milieu d'une application sombre : le contraste sautait a chaque
passage d'une page a l'edition d'un document.

Les surfaces, bordures, textes et etats colores suivent desormais la
palette commune. Les champs natifs (date, nombre, cases a cocher)
recoivent color-scheme: dark pour que le calendrier et les widgets
systeme s'affichent en sombre eux aussi.

Les fiches de metadonnees se repartissent sur 2 puis 3 colonnes selon la
largeur disponible, au lieu d'une seule colonne.

Le bouton « Annuler » du bandeau de tagging devient « Retour a
l'edition », qui decrit son action reelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:50:02 +02:00
aa365dbb63 refactor(ui): passe les pages en pleine largeur
Chaque page plafonnait sa largeur differemment (max-w-4xl pour Config,
5xl pour IA, 6xl pour l'accueil et les documents, 7xl pour les revenus
et les depenses) : sur un ecran large, les donnees se tassaient au
centre. Les pages n'ont plus de plafond, le contenu occupe l'ecran avec
une marge laterale fixe.

Pour tirer parti de la place gagnee : Config affiche ses deux sections
cote a cote, et le split apercu PDF / donnees passe de 50-50 a 40-60 en
faveur des donnees.

Pendant le tagging, le bouton « Annuler » de l'en-tete d'edition est
masque : il faisait doublon avec celui du bandeau de tagging, qui a un
sens different (retour a l'edition, et non abandon). La sortie vers la
liste reste le fil d'Ariane.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:49:43 +02:00
baeabb72d2 feat(ui): pose un design system unique pour toute l'interface
Les pages melangeaient deux themes (sombre pour les tableaux de bord,
clair pour le flux d'extraction) et repetaient des utilitaires Tailwind
divergents : trois styles de boutons, quatre variantes de cartes, des
champs de saisie a paddings differents.

Definit dans style.css une palette unique (gray-950 fond, gray-900
surfaces, gray-700 bordures, blue-600 accent) et les classes composants
associees : page, card, btn, input, table, badge, spinner, empty-state.
Le shell s'y aligne et sa navigation est generee depuis une liste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:49:32 +02:00
c79ecc45ff feat: extraction locataires et opérations par cellules de tableau
Remplace les parseurs texte+regex (fragiles sur l'alignement en colonnes des
PDF Oralia mal construits) par une extraction géométrique : reconstruction des
lignes visuelles par regroupement vertical tolérant des mots, puis affectation
de chaque valeur à sa colonne via les filets du tableau (pdfplumber find_tables).

Corrections apportées :
- locataires : montant/libellé « divers » dans la bonne colonne (plus le total
  cumulé du lot), nom de locataire correct (le logo/en-tête hors filets est
  ignoré), lignes multi-période et pages recollées.
- opérations : fournisseur séparé de la description (TOTALENERGIES ≠ DIDIER
  NETTOYAGE, PPR ≠ BOUVARD), colonne Déductible remplie, Débit/Crédit distingués,
  fournisseur des honoraires reporté sur le bloc, fragments de description
  recollés (LATAPY, AUDOUIN).
- code lot : gère « S10 - », « S 17 - » (espace) et « S01 SOLDE » (sans tiret).

Branchés dans extractor.py avec repli sur les anciens parseurs si un tableau n'a
pas de filets détectables. Validés par réconciliation comptable : locataires
124/124 lots, opérations 7/7 PDF et 25/25 catégories, au centime.

Ajoute le bouton « Relancer l'extraction » dans l'écran d'édition : re-extrait
depuis le PDF stocké et met en évidence les différences avec la version
précédente (panneau récapitulatif + anneaux « modifié » sur les cartes). Le diff
des opérations s'aligne par contenu (robuste aux changements d'ordre/nombre).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 21:29:04 +02:00
2d8b2ff42f feat: apercu PDF via PDF.js (rendu portable, build legacy)
Remplace l'<iframe> (lecteur PDF natif du moteur) par un rendu PDF.js
sur <canvas>, une page par canvas empilee et scrollable. Rendu
identique partout (Qt WebEngine, WebView2, navigateur), worker bundle
localement par Vite -> fonctionne hors-ligne.

Utilise le build *legacy* de pdfjs-dist : il embarque les polyfills
requis par les Chromium embarques (Qt WebEngine, WebView2), plus
anciens que Chrome. Le build par defaut appelle
`Map.prototype.getOrInsertComputed` (proposition JS recente) sans
polyfill, ce qui cassait silencieusement le rendu dans la fenetre
bureau. Le catch logue desormais l'erreur au lieu de l'avaler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 17:22:20 +02:00
bd8b9a044c feat: add config page with LLM settings and tag management
Add ConfigPage.vue with two sections: Ollama configuration (URL, model,
timeout) with source badges and per-field reset, and tag management with
inline rename and creation. Add /config route and nav link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:09:37 +01:00
4fe6a4b2c9 feat: first IA page 2026-02-13 12:18:24 +01:00
5c9a8c9b5e feat: highlight source element when navigating from tables to edit page
Clicking the pencil icon in revenus/depenses tables now passes query
params to identify the source row. The edit page auto-expands the
matching section, scrolls to the element, and briefly highlights it
with a blue ring that fades after 2 seconds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 06:16:29 +01:00
d8b2278491 feat: upload PDF file on save via multipart FormData
Switch save endpoint from JSON to multipart upload so the PDF file is
sent alongside extracted data and tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 05:34:34 +01:00
a119514319 refactor: replace pdfjs-dist with native browser iframe for PDF preview
Remove pdfjs-dist dependency and simplify PdfPreview component to use
a native browser iframe, reducing bundle size and complexity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 05:34:20 +01:00
4f0ca67dc4 feat: reimport pdf 2026-01-22 21:23:46 +01:00
981fabcc27 feat: add rental income dashboard with comprehensive analytics
- Add new /api/revenus endpoints for rental income data
  - GET /summary: KPIs, monthly trends, breakdown by property, top unpaid
  - GET /details: detailed rental records with filtering
  - GET /by-lot: revenue aggregation by unit
  - GET /immeubles: properties list with revenue stats

- Add RevenusPage with full dashboard layout
  - 6 KPI cards: total revenue, payments, unpaid, collection rate, active tenants, occupied units
  - Monthly evolution chart (rent, payments, unpaid)
  - Property breakdown donut chart
  - Top unpaid tenants list
  - Detailed revenue table with pagination and CSV export

- Add filters panel (property, type, dates, unpaid only, history months)
- Display property address instead of code in all components
- Add navigation link in header (Revenus)
2026-01-20 10:05:57 +01:00
281f69f39e feat: enhance homepage with financial summary and sparklines
- Add dashboard API endpoints for financial summary, recent revenus, monthly trends, and immeuble shortcuts
- Create new dashboard components: FinancialSummary with sparklines, QuickActions, RecentRevenus, MiniTrendChart, ImmeubleShortcuts
- Refactor HomePage with prominent drag & drop zone and data-driven cards
- Financial cards now show last document data with 6-month trend sparklines in background
- Remove redundant import button, keep single upload zone at top
2026-01-20 04:53:04 +01:00
cae8d5b963 feat: add inline editing for extracted data and autocomplete for tagging
- Add EditableField component for inline editing of any field
- Update DataRow, LocataireCard, OperationCard to support inline editing
- Add CRUD operations for locataires and operations (add/remove)
- Update JsonViewer to propagate changes via v-model
- Add TagAutocomplete component with search/filter functionality
- Replace select dropdown with autocomplete in TaggingStep
2026-01-19 22:02:28 +01:00
aac4d194e3 feat: add analytics 2026-01-19 21:40:10 +01:00
0fd6bdaeb3 feat: add depense tagging 2026-01-19 05:19:11 +01:00
c5e51a7513 feat: add homepage 2026-01-18 21:11:35 +01:00
ee1db93298 feat: fix parsing 2026-01-18 10:33:09 +01:00
6bad5fbaf9 feat: init plesna-gerance - extracteur de comptes rendus de gerance
- Backend Python (uv + click + FastAPI)
  - CLI: plesna-gerance extract <pdf> pour extraire les donnees
  - CLI: plesna-gerance serve pour lancer le serveur API
  - API REST: POST /api/extract pour upload et extraction de PDF
  - Parsers modulaires: metadata, locataires, operations
  - Utilise pdftotext (poppler-utils) pour l'extraction de texte

- Frontend Vue.js + Tailwind CSS
  - Interface split-screen: PDF a gauche, donnees a droite
  - Preview PDF avec zoom et navigation pages (pdf.js)
  - Visualisation structuree des donnees extraites
  - Sections depliables: metadata, locataires, operations
  - Drag & drop pour upload de PDF
  - Extraction automatique a la selection du fichier
2026-01-18 05:36:27 +01:00