Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,22 @@ STRIPE_SECRET=sk_live_...
# Si Stripe Connect (une cle plateforme pour tous les sous-comptes) :
# STRIPE_PLATFORM_SECRET=sk_live_...
# Les stripe_account_id (acct_xxx) se configurent dans company.json

# Rappels fiscaux J-15 (Resend + PM2 cron)
# https://resend.com — domaine FROM verifie obligatoire
RESEND_API_KEY=
REMINDER_EMAIL_TO=
REMINDER_EMAIL_FROM=Comptable <yourmail@yourdomain.com>
REMINDER_LEAD_DAYS=15
REMINDER_TIMEZONE=Europe/Paris
REMINDER_DRY_RUN=false

# Overrides montants rappels (optionnel)
# IS_N1_EUR=12000
# CFE_ANNUAL_OVERRIDE_EUR=500
# GREFFE_FEE_EUR=45
#
# TVA CA3 : forcer le montant du prochain rappel (€ TTC à payer, période = mois M-1
# avant l'échéance du 25/MM). Utile si journal-entries.json n'est pas encore à jour.
# Ex. échéance 25/05/2026 → période 2026-04. Retirer la variable une fois le journal OK.
# TVA_OVERRIDE_EUR=1234.56
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ node_modules/
output/
company.json
data/transactions/
data/journal-entries.json
data/reminders-sent.json
data/bilan-closing.json
data/bilan-closing-*.json
data/journal-entries.demo-backup.json
config/qonto-label-rules.local.json
!data/examples/
__pycache__/
evals-workspace/
evals/.venv/
Expand Down
98 changes: 97 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,107 @@ Prérequis : `npm install`, puis `cp company.example.json company.json` et rempl

---

## Rappels fiscaux J-15 (e-mail automatique)

Pour les **SASU simples** (IS au réel, TVA réelle normale mensuelle, clôture au 31/12, sans salariés), Paperasse peut envoyer un **rappel par e-mail 15 jours avant** chaque échéance, avec le **montant estimé** et la **justification du calcul** (journal, bilan, formules IS/TVA).

| Obligation | Échéance type |
|------------|----------------|
| TVA (CA3) | 25 du mois suivant |
| Acomptes IS (×4) | 15 mars, juin, sept., déc. |
| Solde IS | 15 mai |
| Liasse IS (2065) | 2e jour ouvré après le 1er mai |
| AG / approbation des comptes | 6 mois après clôture |
| Dépôt au greffe | 30 jours après l’AG |
| CFE | 15 décembre |
| DAS2, rappel IR perso | selon calendrier |

**Calculs déterministes** (pas de LLM pour les montants) :

- **IS** : 25 % × IS N-1 (bilan / `company.json` / override `.env`)
- **TVA** : TVA collectée (44571) − TVA déductible (44566) sur le mois déclaré
- **CFE / greffe** : saisie manuelle ou overrides

### Configuration

1. Copier les variables Resend dans `.env` (voir `.env.example`).
2. Vérifier un **domaine d’envoi** sur [resend.com](https://resend.com/domains) (`REMINDER_EMAIL_FROM` ne peut pas être `@gmail.com`).
3. Tenir le journal à jour (`data/journal-entries.json`) pour des montants TVA fiables.

### Journal Qonto → montants TVA des rappels

Les rappels **TVA** lisent `data/journal-entries.json` (comptes **44571*** collectée, **44566*** / **44562*** déductible sur le mois déclaré). Un simple `fetch:qonto` ne suffit pas : il remplit seulement `data/transactions/`.

**`npm run journal:qonto`** enchaîne :

1. **`fetch:qonto`** — synchronise les opérations Qonto vers `data/transactions/*.json`
2. **`qonto-to-journal.js`** — mappe les catégories Qonto vers le PCG, ventile la TVA (réel normal), écrit les écritures **BQ** dans `journal-entries.json`

Règles libellés spécifiques (clients récurrents, fournisseurs) : fichier optionnel `config/qonto-label-rules.local.json` (modèle : `config/qonto-label-rules.example.json`, gitignored).

**`npm run journal:an`** (optionnel, recommandé) fusionne le bilan de clôture N-1 (`data/bilan-closing.json` ou `bilan-closing-YYYY.json`), l’affectation du résultat (`fiscal_affectation_*` dans `company.json`) et les écritures BQ de l’exercice.

```bash
npm run journal:qonto
npm run journal:an # si bilan Dougs / export disponible
npm run fec
npm run reminders:preview
```

| Commande | Sortie |
|----------|--------|
| `fetch:qonto` | `data/transactions/` uniquement |
| `journal:qonto` | transactions + **`journal-entries.json`** (BQ + TVA) |
| `journal:an` | AN + OD affectation + BQ consolidé |

Période CA3 : échéance du **25/MM** = TVA du **mois M−1**.

**Montant TVA provisoire** — si le journal n’est pas prêt avant le J-15, forcer le montant du prochain rappel CA3 dans `.env` :

```bash
# Ex. CA3 du 25/05/2026 → période TVA 2026-04 (avril)
TVA_OVERRIDE_EUR=1234.56
```

Le calculateur utilise ce montant comme **confirmé** (prioritaire sur le journal). Retirer la variable dès que `journal-entries.json` contient les écritures TVA du mois concerné. Voir aussi `.env.example`.

```bash
npm run reminders:dry-run # aperçu sans envoi
npm run reminders:send # envoi des rappels du jour (J-15)
npm run reminders:preview -- --date 2026-02-28 # simuler une date
```

### PM2 (cron quotidien 08:00 Paris)

```bash
npm run pm2:reminders
pm2 save
pm2 logs paperasse-reminders
```

**Windows — persistance au redémarrage** : `pm2 save` seul ne suffit pas. Installer le démarrage automatique :

```powershell
npm install -g pm2-windows-startup
pm2-startup install
pm2 save
```

Cela ajoute une entrée au démarrage de session (registre utilisateur) qui exécute `pm2 resurrect` et restaure `paperasse-reminders` avec les autres apps PM2 sauvegardées.

Fichier `ecosystem.config.cjs` : `cron_restart: '0 8 * * *'`, `autorestart: false`. Les envois déjà faits sont journalisés dans `data/reminders-sent.json` (gitignored) pour éviter les doublons.

Calendrier et profils : `config/reminders.json`. Code : `lib/reminders/`.

> **Note** : la CA3 du 25/MM porte sur les opérations du **mois M−1** (ex. paiement du 25/05 = TVA d’avril). Le crédit de TVA (44567) n’est pas imputé automatiquement en v1.

---

## Garde-fous

- **Contexte entreprise** : chaque skill vérifie les informations minimales (raison sociale, SIREN, forme juridique, régime TVA) avant de procéder. Si `company.json` existe, il est lu automatiquement. Sinon, le skill pose les questions.

- **Échéances fiscales** : le skill comptable affiche les prochaines échéances à chaque conversation (acomptes IS, TVA, etc.).
- **Échéances fiscales** : le skill comptable affiche les prochaines échéances à chaque conversation (acomptes IS, TVA, etc.). En production, `npm run reminders:send` ou PM2 peut les rappeler par e-mail à J-15.

- **Fraîcheur des données** : chaque skill a une date `last_updated`. S'il a plus de 6 mois, l'agent vérifie les chiffres en ligne avant de répondre. Le législateur français change les règles plus souvent que vous changez de mot de passe. Contrairement à votre mot de passe, ça peut coûter cher.

Expand Down
7 changes: 7 additions & 0 deletions company.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,12 @@
"escompte_label": "Pas d'escompte pour paiement anticipe",
"recovery_fee": 40,
"_comment": "late_penalty_rate: '3x_legal' (defaut legal si non precise) ou taux fixe (ex 10.15). escompte: 'none' ou taux en %. recovery_fee fixe a 40 EUR par la loi."
},
"reminders": {
"_comment": "Rappels J-15 (npm run reminders:send / PM2). Overrides optionnels — sinon calcul depuis bilan local (data/bilan-closing.json) ou journal.",
"is_n1_eur": null,
"cfe_annual_eur": null,
"greffe_fee_eur": 45,
"depot_confidentialite": false
}
}
11 changes: 11 additions & 0 deletions config/qonto-label-rules.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"_comment": "Copier vers config/qonto-label-rules.local.json (gitignored) pour des règles libellé → PCG spécifiques à votre activité (clients, fournisseurs récurrents).",
"label_rules": [
{
"pattern": "NOM CLIENT FACTURE",
"account": "706",
"label": "Ventes prestations",
"vat": "full"
}
]
}
138 changes: 138 additions & 0 deletions config/reminders.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
{
"_meta": {
"description": "Obligations fiscales et juridiques — échéances générées pour company.json",
"lead_days_default": 15,
"timezone": "Europe/Paris"
},
"profiles": {
"sasu_is_tva_normal": {
"match": {
"legal_form": ["SASU", "SAS", "SARL", "EURL", "SA"],
"tax.regime_is": ["reel_normal", "reel_simplifie"],
"tax.regime_tva": ["reel_normal"]
},
"obligations": [
{
"id": "TVA_CA3",
"title": "Déclaration et paiement TVA (CA3)",
"type": "payment",
"schedule": "monthly_day",
"day": 25,
"form": "CA3",
"calculator": "tva"
},
{
"id": "IS_ACOMPTE_1",
"title": "Acompte IS n°1",
"type": "payment",
"schedule": "yearly",
"month": 3,
"day": 15,
"form": "2571",
"calculator": "is_acompte",
"acompte_index": 1
},
{
"id": "IS_ACOMPTE_2",
"title": "Acompte IS n°2",
"type": "payment",
"schedule": "yearly",
"month": 6,
"day": 15,
"form": "2571",
"calculator": "is_acompte",
"acompte_index": 2
},
{
"id": "IS_ACOMPTE_3",
"title": "Acompte IS n°3",
"type": "payment",
"schedule": "yearly",
"month": 9,
"day": 15,
"form": "2571",
"calculator": "is_acompte",
"acompte_index": 3
},
{
"id": "IS_ACOMPTE_4",
"title": "Acompte IS n°4",
"type": "payment",
"schedule": "yearly",
"month": 12,
"day": 15,
"form": "2571",
"calculator": "is_acompte",
"acompte_index": 4
},
{
"id": "IS_SOLDE",
"title": "Solde IS (exercice clos 31/12)",
"type": "payment",
"schedule": "yearly",
"month": 5,
"day": 15,
"form": "2572",
"calculator": "is_solde"
},
{
"id": "LIASSE_IS",
"title": "Liasse fiscale IS (télédéclaration)",
"type": "declaration",
"schedule": "second_business_day_after",
"anchor_month": 5,
"anchor_day": 1,
"form": "2065"
},
{
"id": "AG_APPROBATION",
"title": "AG / décision associé unique — approbation des comptes",
"type": "legal",
"schedule": "months_after_fiscal_end",
"months": 6,
"form": "PV AG"
},
{
"id": "DEPOT_GREFFE",
"title": "Dépôt des comptes au greffe",
"type": "payment",
"schedule": "days_after_ag",
"days": 30,
"form": "Infogreffe",
"calculator": "greffe"
},
{
"id": "CFE",
"title": "Cotisation foncière des entreprises (CFE)",
"type": "payment",
"schedule": "yearly",
"month": 12,
"day": 15,
"calculator": "cfe"
},
{
"id": "DAS2",
"title": "Déclaration DAS2 (honoraires > 1 200 €)",
"type": "declaration",
"schedule": "yearly",
"month": 3,
"day": 31,
"form": "DAS2"
},
{
"id": "IR_PERSO",
"title": "Déclaration IR personnelle (rappel)",
"type": "personal",
"schedule": "yearly",
"month": 5,
"day": 20,
"form": "2042"
}
],
"skip_if": {
"employees_gte": 1,
"hide_ids": ["DSN"]
}
}
}
}
7 changes: 7 additions & 0 deletions data/examples/bilan-closing.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"_comment": "Exemple fictif pour les tests et la doc — ne pas utiliser pour une vraie société",
"as_of": "2025-12-31",
"accounts": [
{ "account": "129", "label": "Resultat exercice (exemple)", "debit": 0, "credit": 40000 }
]
}
Loading