# Rapport de la version 1.2.0 — juillet 2026

Application de gestion de **STE MOBDIE PRIVÉ**, en production sur app.mobdie.ma.
Ce rapport est écrit pour être lu sans connaissances techniques.

---

## À faire après extraction de l'archive

L'archive `mobdie-maj-v1.2.0.tar.gz` ne contient que les fichiers modifiés ou
ajoutés, à extraire par-dessus l'installation existante, à sa racine. Elle
inclut les **feuilles de style recompilées** (`public/build/`) : l'hébergement
mutualisé ne sait pas les reconstruire, et sans elles les écrans resteraient
sans mise en forme.

Trois commandes, dans cet ordre, depuis le dossier de l'application :

```bash
php artisan migrate --force
php artisan db:seed --class='Database\Seeders\SettingsSeeder' --force
php artisan db:seed --class='Database\Seeders\CommissionSchemeSeeder' --force
```

La migration ajoute le lien entre facture et échéance, le délai de règlement,
le régime fiscal, le taux de TVA des catégories et le rattachement des tiers aux
clients. Aucune migration existante n'a été modifiée.

Puis le vidage et la reconstruction des caches :

```bash
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan filament:optimize
```

Enfin, deux commandes de remise en ordre des données, à lancer une seule fois :

```bash
# Rend le compte de résultat hors taxes (507 opérations sur les données réelles)
php artisan mobdie:ventiler-tva

# Remplit l'écran « Tiers », resté vide. Le seuil de trois occurrences écarte
# les libellés qui décrivent une opération plutôt qu'un tiers (voir §1).
php artisan mobdie:reconstruire-tiers --min-operations=3
```

Chacune accepte `--dry-run` pour voir ce qu'elle ferait sans rien modifier.

Une commande de secours existe si la matrice de permissions a déjà été
enregistrée avant cette mise à jour, et a donc effacé les droits des rôles :

```bash
php artisan mobdie:reparer-permissions
```

---

## 1. Ce qui a été corrigé

### La matrice de permissions effaçait tous les droits

C'était le défaut le plus grave. Les noms de permissions contiennent un point
(« clients.voir »). Le composant d'affichage lisait ce point comme un
changement de niveau et perdait le vrai nom. Deux conséquences : toutes les
cases apparaissaient décochées alors que les rôles avaient bien leurs droits en
base, et un clic sur « Enregistrer la matrice » retirait la totalité des droits
des trois rôles d'un coup.

Le point est désormais encodé avant d'être affiché, et décodé avant
d'enregistrer — exactement comme le fait déjà l'écran Réglages. Quatre tests
verrouillent le comportement, dont un qui vérifie qu'un enregistrement **sans
aucune modification** ne retire rien à personne.

Une recherche a été menée dans tout le projet pour trouver d'autres liaisons
souffrant du même défaut : la matrice était la seule restante.

### Tous les onglets de la liste des clients renvoyaient une erreur 500

Le diagnostic transmis attribuait la panne à une mauvaise classe d'onglet. La
vérification dans la bibliothèque réellement installée montre autre chose : la
classe incriminée n'existe plus dans cette version, et celle qui était employée
est la bonne.

La cause réelle est plus subtile. Le nom donné au paramètre des filtres
d'onglet doit être exactement « query ». Il était nommé « q ». La bibliothèque,
ne reconnaissant pas ce nom, fabriquait alors un objet vide qu'elle passait à la
place de la requête réelle, ce qui faisait tomber la page. Seul l'onglet
« Tous », qui ne filtre rien, y échappait — d'où le symptôme observé.

Les sept onglets sont désormais chargés par les tests, **pour chacun des quatre
rôles**.

### Le compte de résultat était calculé toutes taxes comprises

Un compte de produits et charges se tient hors taxes : la TVA collectée est une
dette envers l'État, pas un produit. Le calcul a été repris entièrement — compte
de résultat, balance par catégorie, tableau de bord et exports raisonnent
maintenant sur le montant hors taxes. La TVA collectée, la TVA déductible et la
TVA due à l'État sont affichées à part, en tête d'écran, et une phrase rappelle
la règle.

Un point important : le journal repris portait un taux de TVA de zéro sur ses
1 818 opérations, si bien que le hors taxes valait le toutes taxes. Le taux se
déclare désormais **sur la catégorie comptable**, et la commande
`mobdie:ventiler-tva` l'applique rétroactivement. Sur les données réelles, elle
a ventilé 507 opérations de recettes.

Après cette remise en ordre, le chiffre d'affaires 2026 ressort à
**12 916,65 DH** au lieu de 15 500 DH. La cible annoncée était 12 916,67 DH :
l'écart de deux centimes vient de ce que chaque encaissement est arrondi au
centime individuellement, comme l'exige la comptabilité, plutôt que la somme
divisée une seule fois. C'est le total des montants hors taxes réellement
inscrits au journal, et un test vérifie cette égalité.

### Cinq écrans s'affichaient sans aucune mise en forme

Les compteurs de Dossiers incomplets, la fiche du Prêt Forsa, les tableaux des
Rapports comptables, le Registre légal et la Matrice de permissions
s'affichaient en texte brut.

La feuille de style du panneau était celle, précompilée, fournie par la
bibliothèque : elle ne contenait que les styles des composants standards. Tout
ce que nos propres écrans employaient n'était donc jamais produit. Une feuille
de style propre à l'application a été mise en place ; elle balaie nos vues, nos
écrans et les composants de la bibliothèque. Les cinq écrans ont été vérifiés un
par un dans le navigateur.

### Deux modules qui ne pouvaient rien produire

**Aucun barème de commission n'existait**, si bien qu'aucune commission ne
pouvait naître d'un encaissement. Le barème convenu — 100 DH par encaissement de
renouvellement pour Salima — est désormais posé à l'installation, et l'écran
vide propose un bouton « Créer le barème par défaut ».

**Aucun tiers n'existait et aucun ne se créait** : les opérations importées
portaient le nom du tiers en texte libre sans jamais le rattacher à une fiche.
La commande `mobdie:reconstruire-tiers` parcourt le journal, regroupe les
variantes d'écriture (majuscules, accents, espaces multiples), crée les fiches,
rattache les opérations et relie les tiers de type client au client domicilié
correspondant. Sur les données réelles : **936 tiers reconnus, 1 783 opérations
rattachées, 13 tiers reliés à un client**.

Une réserve, dite franchement : le libellé du journal mélange des noms de tiers
(« STE ALPHA ») et des descriptions d'opération (« 15 chaises »). La
reconstruction crée donc aussi des fiches qui n'en sont pas. L'option
`--min-operations=3` ne retient que les tiers revenant au moins trois fois et
ramène la liste à 108 entrées, toutes pertinentes. C'est la variante
recommandée ; la commande le signale d'elle-même.

### Autres défauts relevés à l'inspection

- Le tableau de bord annonçait une ancienneté moyenne de créance de **−224 j** :
  l'écart de dates était compté à l'envers.
- La carte « Montant impayé » du tableau de bord renvoyait vers l'onglet
  « Tous » au lieu de « En retard ».
- Les actions du journal débordaient de la largeur du tableau.
- Un refus d'accès affichait une page anglaise, « 403 | FORBIDDEN », sans
  explication ni moyen de revenir. Les pages 403, 404, 419, 500 et 503 sont
  maintenant rédigées en français et aux couleurs de l'application.
- L'onglet Société des Réglages s'ouvrait sur un encadré gris vide.
- Les listes vides affichaient « Aucun(e) Commissions », « Aucun(e) Analyses
  IA », avec une croix grise qui faisait passer une liste normalement vide pour
  une panne. Chaque écran a maintenant sa phrase, sa précision utile et son
  icône.
- Le logo ne se chargeait pas. Il est désormais dessiné directement dans la
  page, recadré sur son tracé — il ne peut donc plus manquer, et son texte
  s'inverse tout seul entre le thème clair et le thème sombre. Le favicon livré
  était un **fichier vide** ; il a été régénéré depuis le sigle de la charte, en
  quatre tailles.
- Le registre légal annonçait « 56 sociétés » sur un périmètre discutable. Le
  registre de l'article 544-1 porte sur toute société domiciliée à un moment
  quelconque de l'année, **y compris celles sorties en cours d'année et celles
  domiciliées à titre gratuit** : ces lignes n'étaient donc pas des intruses.
  Le périmètre est maintenant expliqué en une phrase au-dessus du tableau, et
  chaque société affiche sa période de domiciliation dans l'exercice et sa date
  de sortie s'il y en a une. Le décompte passe à 63 sociétés pour 2026, le
  critère étant désormais le contrat et non le statut du jour.
- La facture portait la même date en émission et en échéance. Un délai de
  règlement paramétrable, à trente jours par défaut, est appliqué et reste
  modifiable facture par facture.
- Le formulaire de facture disait « Ajouter à lignes » et n'affichait aucun
  total. Il dit « Ajouter une ligne » et affiche sous le tableau, **en temps
  réel**, le total hors taxes, la TVA, le total TTC et le montant en toutes
  lettres. Le champ de retenue à la source ne paraît que si la retenue est
  activée.

---

## 2. Comment fonctionne désormais la chaîne devis → facture → encaissement

C'est le cœur du métier, et il était cassé en trois endroits : rien ne
permettait de produire la facture d'une échéance, une facture encaissée ne
créait aucune écriture, et rien ne reliait un devis à un contrat.

**Une règle gouverne tout l'ensemble : le paiement est le seul événement qui
crée une écriture de trésorerie.** Ni le devis, ni la facture, ni l'échéance
n'écrivent au journal. Sans cette règle, le même encaissement serait compté deux
fois.

### Le parcours

**1. Le devis.** Depuis la fiche d'un client domicilié ou d'un prospect, le
bouton « Établir un devis » crée un devis déjà rempli : le client, la prestation
« Domiciliation — période du … au … », le montant du contrat en cours ou celui
que vous proposez, et la TVA du réglage. Le devis reste ce qu'il était :
envoyable par e-mail, avec son statut et sa date de validité.

**2. Du devis au contrat.** Quand le client accepte, « Transformer en contrat »
crée le contrat de domiciliation avec la durée et le montant du devis, génère
l'échéancier, et conserve le lien vers le devis d'origine. Le devis passe en
« transformé » et ne peut plus l'être une seconde fois. Un prospect qui signe
devient automatiquement un client actif.

**3. De l'échéance à la facture.** Sur chaque échéance, « Générer la facture »
produit une facture d'une seule ligne : « Domiciliation — <raison sociale> —
période du … au … », quantité 1, prix unitaire égal au montant hors taxes de
l'échéance, taux de TVA de l'échéance. La facture reprend la date d'échéance,
reste en brouillon, et les deux fiches se pointent mutuellement.

La même action existe **en lot** : sélectionner vingt échéances et produire les
vingt factures d'un seul geste. C'est ce qu'il faut pour rattraper les
62 impayés. Les échéances déjà facturées sont ignorées, jamais dupliquées.

**4. L'encaissement.** Enregistrer un paiement passe l'échéance en « payée »,
solde la facture liée s'il y en a une, crée l'écriture de trésorerie — une
seule — et génère la commission. Si l'échéance n'a pas encore de facture,
l'écran propose de la produire dans la foulée : une recette encaissée sans
facture est un problème fiscal.

**5. Le règlement vu depuis la facture.** Sur une facture rattachée à une
échéance, « Enregistrer le règlement » renvoie vers le paiement de cette
échéance plutôt que de créer une écriture parallèle. Sur une facture libre, sans
échéance, il crée le paiement et l'écriture directement.

### Défaire sans rien casser

Annuler une facture détache l'échéance et la remet dans l'état qu'elle avait
avant d'être facturée. Supprimer un paiement supprime l'écriture de trésorerie,
la commission acquise, et remet l'échéance et la facture exactement comme elles
étaient. Une facture réglée ne peut pas être annulée sans supprimer d'abord son
paiement, et le message le dit clairement.

### Ce que l'on voit à l'écran

Sur la fiche d'un client, l'échéancier affiche pour chaque ligne le numéro, la
date, le montant, le statut, **le numéro de facture** et **la date de
paiement** : une échéance sans facture se repère au premier coup d'œil, en
rouge.

Un nouvel écran, **« Échéancier global »**, réunit toutes les échéances de tous
les clients. Il se filtre par statut, par période, par commercial et selon
qu'une facture existe ou non, affiche les totaux en pied de colonne et propose
les actions en lot. C'est le poste de travail du recouvrement, et il n'existait
pas : l'échéancier n'était consultable que client par client. Quatre chiffres le
résument en tête : reste à encaisser, impayés échus, échéances sans facture,
encaissé.

---

## 3. Ce qui a été repris de l'application jumelle

L'application Ruwad est en production depuis un an et a émis de vraies factures.
Ses modules de facturation ont été repris plutôt que de continuer à maintenir
une version appauvrie.

### Repris à l'identique

| Élément | Rôle |
|---|---|
| `app/Support/PdfText.php` | Nettoie les caractères que le moteur PDF ne sait pas dessiner et qui s'affichaient en « ? » |
| `app/Support/Money.php` | Mise en forme des montants dans les documents PDF |

### Repris et adaptés

| Élément | Adaptation, et pourquoi |
|---|---|
| Les trois états fiscaux (TVA, sans TVA, retenue à la source) | Modélisés proprement chez Ruwad, gérés à moitié chez Mobdie. Repris et alignés sur les statuts déjà en base, pour ne rien casser des documents existants |
| Les états d'une facture et d'un devis | Complétés d'un statut « transformé en contrat », propre au métier de la domiciliation |
| `FrenchNumber` (montant en toutes lettres) | Structure reprise. L'orthographe classique (« vingt et un », « soixante et onze ») a été **conservée** : c'est celle des attestations et factures déjà émises, et en changer aurait modifié tous les documents. Un défaut d'accord commun aux deux applications a été corrigé au passage : « deux cent mille » et non « deux cents mille » |
| `InvoiceService` et `QuoteService` | Numérotation par série et par exercice, calculs et transitions de statut repris. Le domaine, lui, diffère : Mobdie facture des **échéances de domiciliation**, Ruwad des décomptes de marché public. La mécanique est celle de Ruwad, les objets sont ceux de Mobdie |
| `InvoicePolicy` et `QuotePolicy` | Portées aux quatre rôles de Mobdie, en gardant la règle que le gestionnaire ne génère pas de facture |
| Les gabarits PDF de facture et de devis | En-tête société, cachet centré, **deux cases de signature distinctes**, pied de page légal — repris tels quels, aux couleurs de la charte Mobdie (violet et orange au lieu du bleu et or de Ruwad) |
| Le CPC et le journal en PDF | Mobdie ne les avait qu'en Excel ; ils existent maintenant aussi en PDF |
| Le relevé de compte d'un tiers | **Transformé en relevé de compte du domicilié** : toutes ses échéances, ce qui est payé, ce qui reste dû, le solde, et le montant restant dû en toutes lettres. C'est la pièce à joindre à une relance ferme, et elle change tout dans une discussion de recouvrement |

Les listes de factures et de devis ont été comparées à celles de Ruwad et
enrichies de ce qui y était meilleur : statut en pastille colorée, filtre par
période, totaux en pied de colonne, menu d'actions groupées, et surtout le lien
vers l'échéance et vers le client, qui manquait entièrement.

### Volontairement non repris

- **Le modèle d'e-mail de devis.** Mobdie dispose déjà d'un mécanisme
  équivalent : objet et corps configurables dans les Réglages, avec variables,
  modifiables avant chaque envoi. Le reprendre aurait fait doublon.
- Les modules hors périmètre, comme convenu : marchés publics, portail
  investisseur, paie, congés, notes de frais, feuilles de temps, bons de
  livraison.

---

## 4. Ce que je n'ai pas pu faire, et pourquoi

**Le chiffre d'affaires 2026 ressort à 12 916,65 DH, pas 12 916,67 DH.**
L'écart est de deux centimes. Il vient de ce que chaque encaissement est converti
en hors taxes et arrondi au centime individuellement — c'est la règle comptable :
le hors taxes et la TVA d'une opération doivent redonner son montant exact. La
valeur attendue correspondait à la division du total en une seule fois.
Le chiffre affiché est bien la somme des montants hors taxes inscrits au
journal, et c'est cette égalité que le test vérifie.

**La reconstruction des tiers produit du bruit.** Comme expliqué plus haut, la
colonne du journal mélange des noms de tiers et des descriptions d'opération. Le
programme ne peut pas deviner lesquels sont lesquels ; l'option
`--min-operations=3` est le meilleur compromis disponible et donne une liste
propre de 108 tiers. Un tri à la main reste possible depuis l'écran Tiers.

**Le taux de TVA n'a été appliqué qu'aux recettes.** Les charges du journal
restent à un taux de zéro. Appliquer une TVA déductible aux achats demanderait
de trancher, poste par poste, ce qui est déductible et à quel taux — une
décision comptable, pas technique. Le taux se déclare maintenant sur chaque
catégorie ; il suffira de le renseigner et de relancer `mobdie:ventiler-tva`.

**La vérification visuelle a porté sur le rôle super-administrateur et sur le
rôle gestionnaire.** Les rôles administrateur et commercial sont couverts par
les tests automatiques — toutes les pages, tous les onglets — mais n'ont pas été
parcourus écran par écran dans le navigateur.

---

## 5. Ce qui est vérifié automatiquement

La suite de tests passe de 65 à **119 tests et 540 vérifications**. Les ajouts
portent sur ce qui a fait défaut à la recette :

- la matrice de permissions : accorder, révoquer, et surtout n'amputer personne
  lors d'un enregistrement sans changement ;
- les sept onglets de la liste des clients, pour les quatre rôles ;
- le compte de résultat hors taxes, et l'égalité avec la somme des montants hors
  taxes du journal ;
- la chaîne complète : devis pré-rempli, transformation en contrat, génération
  de facture unitaire et en lot, encaissement produisant **une seule** écriture,
  suppression de paiement remettant tout en état, refus d'annuler une facture
  réglée, délai de règlement ;
- le barème de commission et la reconstruction des tiers ;
- **des tests de fumée qui chargent toutes les pages du panneau pour chacun des
  quatre rôles**, en énumérant les écrans depuis l'application elle-même : un
  écran ajouté demain sera couvert sans qu'on ait à y penser. C'est précisément
  ce qui manquait pour attraper le bug des onglets.

---

*Version 1.2.0 — livrée le 28 juillet 2026.*
