Aller au contenu principal

Règles — Transactions

BR-TX-001 — Déduplication par importHash [DB]

Transaction.importHash String @unique

Chaque transaction importée via CSV reçoit un hash déterministe calculé par le parser à partir des champs significatifs (date, montant, libellé, compte). L'import utilise createMany({ skipDuplicates: true }) : une transaction dont le hash existe déjà est silencieusement ignorée.

Résultat : importer deux fois le même fichier CSV est idempotent. Le compteur ignored dans le résultat d'import indique le nombre de lignes sautées.


BR-TX-002 — Convention de signe [APP]

SigneSens
amount > 0Crédit (entrée d'argent)
amount < 0Débit (sortie d'argent)

Le signe est fixé par le parser au moment de l'import et ne change jamais ensuite. Les calculs analytics filtrent par amount > 0 (crédits) ou amount < 0 (débits) directement.


BR-TX-003 — Transferts internes [APP]

Une transaction isInternal = true représente un transfert entre deux comptes de l'utilisateur. Ces transactions sont exclues de tous les calculs analytics (flux mensuels, répartition par catégorie, résumé).

Détection automatique à l'import

Après chaque import, le système scanne les nouvelles transactions et les compare aux transactions des autres comptes du même utilisateur :

  • Montant absolu identique (|amount_A| === |amount_B|)
  • Signes opposés (un débit + un crédit)
  • Fenêtre temporelle ±2 jours
  • Comptes différents

Si une paire est trouvée, les deux transactions sont marquées isInternal = true et liées via counterpartId (mutuellement référencées) dans une transaction Prisma atomique.

Toggle manuel

L'utilisateur peut basculer isInternal via le bouton ToggleInternalButton. Si la transaction a un counterpartId, les deux côtés du transfert sont basculés simultanément (transaction Prisma atomique).


BR-TX-004 — Montants en Decimal(12, 2) [DB]

Transaction.amount Decimal @db.Decimal(12,2)
Transaction.amountEur Decimal @db.Decimal(12,2)

Les montants sont stockés avec 2 décimales en PostgreSQL via le type Decimal Prisma. Pas de Float pour éviter les erreurs d'arrondi sur les comparaisons (amount === -counterpart).

En JavaScript : Number(tx.amount) uniquement pour l'affichage. Jamais pour les comparaisons (préférer la comparaison Prisma { equals: value }).


BR-TX-005 — Taux de change stocké à la date [DB]

Transaction.fxRate Decimal @db.Decimal(18,8) @default(1)

Le taux EUR appliqué au moment de l'import est stocké dans fxRate. amountEur = amount / fxRate (ou amount * fxRate selon la convention devise). Un taux de 1 signifie que la transaction est déjà en EUR.

Voir Règles — FX pour la politique complète des taux de change.


BR-TX-006 — Source d'import [DB]

L'enum ImportSource trace l'origine de chaque transaction :

ValeurOrigine
CSV_BOURSOExport BoursoBank (opérations)
CSV_REVOLUTExport Revolut
CSV_TRExport Trade Republic
MANUALSaisie manuelle (non implémentée en V1)

CSV_BOURSO_PEA n'a pas de valeur dédiée dans l'enum — les transactions PEA BoursoBank utilisent CSV_BOURSO.


BR-TX-007 — Pagination par défaut 50 [APP]

Les listes de transactions sont paginées avec pageSize = 50 par défaut. Le paramètre page commence à 1. L'API retourne { transactions, total } pour permettre la pagination côté client.


Voir aussi