refactor: remove category rules and related logic from defaults, types, and services for cleaner codebase

This commit is contained in:
Julien Froidefond
2025-11-27 10:41:10 +01:00
parent 2aafce4df0
commit cf109984e5
6 changed files with 5 additions and 135 deletions

View File

@@ -1,4 +1,3 @@
import type { CategoryRule } from "./types"
// ═══════════════════════════════════════════════════════════════════════════
// STRUCTURE HIÉRARCHIQUE DES CATÉGORIES
@@ -986,58 +985,6 @@ export const defaultCategories: CategoryDefinition[] = [
},
]
// ═══════════════════════════════════════════════════════════════════════════
// RÈGLES DE CATÉGORISATION AVANCÉES
// ═══════════════════════════════════════════════════════════════════════════
export interface CategoryRuleDefinition extends Omit<CategoryRule, "id" | "categoryId"> {
categorySlug: string // Référence au slug de la catégorie
}
export const defaultCategoryRules: CategoryRuleDefinition[] = [
// Salaire - patterns typiques de virements salaire
{ categorySlug: "revenus-salaire", pattern: "^VIR(EMENT)? (RECU )?.*SALAIRE", isRegex: true },
{ categorySlug: "revenus-salaire", pattern: "^VIR(EMENT)? (RECU )?.*PAIE", isRegex: true },
// Loyer - patterns de prélèvement loyer
{ categorySlug: "logement-loyer", pattern: "^PRLV.*LOYER", isRegex: true },
{ categorySlug: "logement-loyer", pattern: "^PRLV.*FONCIA", isRegex: true },
{ categorySlug: "logement-loyer", pattern: "^PRLV.*NEXITY", isRegex: true },
// EDF/Engie
{ categorySlug: "logement-electricite", pattern: "^PRLV.*EDF", isRegex: true },
{ categorySlug: "logement-electricite", pattern: "^PRLV.*ENGIE", isRegex: true },
{ categorySlug: "logement-electricite", pattern: "^PRLV.*TOTAL.?ENERGIE", isRegex: true },
// Télécom
{ categorySlug: "abonnements-telecom", pattern: "^PRLV.*FREE( MOBILE)?", isRegex: true },
{ categorySlug: "abonnements-telecom", pattern: "^PRLV.*ORANGE", isRegex: true },
{ categorySlug: "abonnements-telecom", pattern: "^PRLV.*SFR", isRegex: true },
{ categorySlug: "abonnements-telecom", pattern: "^PRLV.*BOUYGUES", isRegex: true },
// Assurances
{ categorySlug: "finance-assurance", pattern: "^PRLV.*AXA", isRegex: true },
{ categorySlug: "finance-assurance", pattern: "^PRLV.*MAIF", isRegex: true },
{ categorySlug: "finance-assurance", pattern: "^PRLV.*MACIF", isRegex: true },
{ categorySlug: "finance-assurance", pattern: "^PRLV.*MATMUT", isRegex: true },
// Impôts
{ categorySlug: "finance-impots", pattern: "^PRLV.*DGFIP", isRegex: true },
{ categorySlug: "finance-impots", pattern: "^PRLV.*TRESOR PUBLIC", isRegex: true },
{ categorySlug: "finance-impots", pattern: "IMPOT", isRegex: false },
// Remboursements
{ categorySlug: "revenus-remboursements", pattern: "^VIR(EMENT)? (RECU )?.*CPAM", isRegex: true },
{ categorySlug: "revenus-remboursements", pattern: "^VIR(EMENT)? (RECU )?.*AMELI", isRegex: true },
{ categorySlug: "revenus-remboursements", pattern: "REMBOURSEMENT", isRegex: false },
// CAF
{ categorySlug: "revenus-allocations", pattern: "^VIR(EMENT)? (RECU )?.*CAF", isRegex: true },
{ categorySlug: "revenus-allocations", pattern: "ALLOCATION", isRegex: false },
// Retraits
{ categorySlug: "divers-retraits", pattern: "^RETRAIT DAB", isRegex: true },
{ categorySlug: "divers-retraits", pattern: "^RET DAB", isRegex: true },
]
// ═══════════════════════════════════════════════════════════════════════════
// DOSSIER RACINE

View File

@@ -48,7 +48,6 @@ const defaultData: BankingData = {
transactions: [],
folders: [defaultRootFolder],
categories: buildCategoriesFromDefaults(),
categoryRules: [],
}
export function loadData(): BankingData {

View File

@@ -43,19 +43,11 @@ export interface Category {
parentId: string | null
}
export interface CategoryRule {
id: string
categoryId: string
pattern: string
isRegex: boolean
}
export interface BankingData {
accounts: Account[]
transactions: Transaction[]
folders: Folder[]
categories: Category[]
categoryRules: CategoryRule[]
}
// OFX Parsed types

View File

@@ -82,20 +82,6 @@ model Category {
parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id], onDelete: Cascade)
children Category[] @relation("CategoryHierarchy")
transactions Transaction[]
rules CategoryRule[]
@@index([parentId])
}
model CategoryRule {
id String @id @default(cuid())
categoryId String
pattern String
isRegex Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
@@index([categoryId])
}

View File

@@ -1,5 +1,5 @@
import { PrismaClient } from "@prisma/client"
import { defaultCategories, defaultCategoryRules, type CategoryDefinition } from "../lib/defaults"
import { defaultCategories, type CategoryDefinition } from "../lib/defaults"
const prisma = new PrismaClient()
@@ -113,51 +113,6 @@ async function main() {
else unchanged++
}
// ═══════════════════════════════════════════════════════════════════════════
// PHASE 3: Sync des règles (optionnel)
// ═══════════════════════════════════════════════════════════════════════════
if (defaultCategoryRules.length > 0) {
console.log("\n" + "═".repeat(50))
console.log("PHASE 3: Règles de catégorisation")
console.log("═".repeat(50))
let rulesCreated = 0
let rulesSkipped = 0
for (const rule of defaultCategoryRules) {
const categoryId = slugToId.get(rule.categorySlug)
if (!categoryId) {
console.log(`⚠️ Catégorie introuvable pour règle: ${rule.categorySlug}`)
rulesSkipped++
continue
}
// Vérifier si la règle existe déjà
const existing = await prisma.categoryRule.findFirst({
where: {
categoryId,
pattern: rule.pattern,
},
})
if (!existing) {
await prisma.categoryRule.create({
data: {
categoryId,
pattern: rule.pattern,
isRegex: rule.isRegex,
},
})
console.log(`✅ Règle créée: ${rule.pattern.substring(0, 40)}...`)
rulesCreated++
} else {
rulesSkipped++
}
}
console.log(`\n📊 Règles: ${rulesCreated} créées, ${rulesSkipped} existantes`)
}
// ═══════════════════════════════════════════════════════════════════════════
// RÉSUMÉ
// ═══════════════════════════════════════════════════════════════════════════
@@ -172,12 +127,10 @@ async function main() {
const totalCategories = await prisma.category.count()
const parentCount = await prisma.category.count({ where: { parentId: null } })
const childCount = await prisma.category.count({ where: { NOT: { parentId: null } } })
const totalRules = await prisma.categoryRule.count()
const totalKeywords = defaultCategories.reduce((sum, c) => sum + c.keywords.length, 0)
console.log("\n📈 Base de données:")
console.log(` Total catégories: ${totalCategories} (${parentCount} parents, ${childCount} enfants)`)
console.log(` Total règles: ${totalRules}`)
console.log(` Total keywords: ${totalKeywords}`)
}

View File

@@ -1,9 +1,9 @@
import { prisma } from "@/lib/prisma"
import type { BankingData, Account, Transaction, Folder, Category, CategoryRule } from "@/lib/types"
import type { BankingData, Account, Transaction, Folder, Category } from "@/lib/types"
export const bankingService = {
async getAllData(): Promise<BankingData> {
const [accounts, transactions, folders, categories, categoryRules] = await Promise.all([
const [accounts, transactions, folders, categories] = await Promise.all([
prisma.account.findMany({
include: {
folder: true,
@@ -17,7 +17,6 @@ export const bankingService = {
}),
prisma.folder.findMany(),
prisma.category.findMany(),
prisma.categoryRule.findMany(),
])
// Transform Prisma models to match our types
@@ -61,12 +60,6 @@ export const bankingService = {
keywords: JSON.parse(c.keywords) as string[],
parentId: c.parentId,
})),
categoryRules: categoryRules.map((r): CategoryRule => ({
id: r.id,
categoryId: r.categoryId,
pattern: r.pattern,
isRegex: r.isRegex,
})),
}
},
}