# TelecomCash — Gestion des ventes et de la trésorerie télécom

Application web (Laravel 12 + MySQL + Blade/Tailwind) de gestion des ventes de tickets, cartes et recharges
(Ooredoo, Orange, Tunisie Telecom… opérateurs ajoutables depuis le back-office), des entrées / sorties d'argent,
des clients, des bénéfices et des rapports. Une API REST sécurisée (`/api/v1`) expose les mêmes règles métier
pour la future application mobile Android / iOS (Flutter recommandé).

## Installation (WAMP / Windows)

```bash
composer install
npm install && npm run build
copy .env.example .env      # puis DB_DATABASE=app, identifiants MySQL, SMTP…
php artisan key:generate
php artisan migrate --seed                     # paramètres, opérateurs, produits, compte admin
php artisan db:seed --class=DemoDataSeeder     # optionnel : 90 jours de données de démonstration
php artisan storage:link
php artisan serve
```

Compte initial : `admin` / `Admin@2026` (variable `ADMIN_INITIAL_PASSWORD` au seed). **À changer dès la première connexion**
(clic sur votre nom en haut à droite). Comptes de démonstration : `gestionnaire`, `caissier`, `lecture` / `Demo@2026`.

> La base `app` doit être en InnoDB (forcé dans `config/database.php` via `DB_ENGINE`).

### Tâches de fond (production)

| Rôle | Commande |
|---|---|
| Planificateur (toutes les minutes, cron ou Planificateur de tâches Windows) | `php artisan schedule:run` |
| File d'attente (envois de rapports) | `php artisan queue:work --tries=3` |

Le planificateur exécute : rapports automatiques (`reports:dispatch`, toutes les 5 min), sauvegarde MySQL compressée
(`app:backup`, 02:00, rétention configurable), purge des jetons expirés.

### E-mail et WhatsApp

- **E-mail** : renseigner `MAIL_MAILER=smtp`, `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME`, `MAIL_PASSWORD`, `MAIL_FROM_ADDRESS` (ou un fournisseur : Mailgun, SES, Brevo…).
- **WhatsApp Business Platform (Cloud API Meta)** : application Meta + compte WhatsApp Business vérifié, puis
  `WHATSAPP_TOKEN` et `WHATSAPP_PHONE_NUMBER_ID` (ou dans Paramètres). Hors de la fenêtre de 24 h, Meta impose un
  modèle approuvé (paramètre `whatsapp_template`) ; les conversations initiées par l'entreprise sont facturées par Meta.
  Sans configuration, le bouton WhatsApp ouvre un partage manuel `wa.me` avec le résumé pré-rempli.

## Prise en main rapide

- **Vendre** (`Alt+N` partout) : touchez les produits (les plus vendus en premier, ★), ou tapez `/` puis « orange 10 » + Entrée.
  Client : tapez un nom ou un numéro, ou créez-le sur place. Mode de paiement mémorisé, monnaie à rendre calculée,
  « Valider et continuer » enchaîne les ventes ; reçu 80 mm imprimable ou envoyé par WhatsApp.
- **Rechercher** (`Ctrl+K`) : clients, ventes, mouvements et produits depuis n'importe quelle page.
- **Accueil** : boutons Nouvelle vente / Encaisser / Dépense / Clôturer / Rapport du jour ; rappel si une journée n'est pas clôturée.
- **Clients** : boutons Vendre, Encaisser (montant dû pré-rempli), Appeler et relance WhatsApp du solde.
- **Dépenses** : raccourcis par catégorie et « Enregistrer et saisir une autre ».
- **Téléphone** : barre d'onglets en bas ; l'application s'installe sur l'écran d'accueil (menu du navigateur
  → « Ajouter à l'écran d'accueil », nécessite HTTPS en production).

## Téléchargement de l'application mobile

- Menu **Application mobile** (bas de la barre latérale, tous les utilisateurs) : bouton « Télécharger l'APK », **QR code** à scanner avec
  le téléphone (lien signé valable 72 h, sans connexion), envoi du lien par WhatsApp, guide d'installation en 4 étapes et adresse du
  serveur à saisir dans l'application (avec son QR code).
- Administrateurs : **publier une version** depuis l'APK compilé sur le PC (`mobile/build/app/outputs/flutter-apk`, release en priorité)
  ou en envoyant un fichier `.apk` (limité par `upload_max_filesize` / `post_max_size` de PHP), notes de version, choix de la version
  proposée, historique avec nombre de téléchargements. Les fichiers sont stockés dans `storage/app/private/mobile` (non publics) et
  vérifiés (archive APK valide, empreinte SHA-256).
- Compiler une version à diffuser : `cd mobile && flutter build apk --release` (APK plus léger qu'une version de test).

## Zones géographiques et carte

- **Zones** (menu Gestion → Zones) : nom, code, description, couleur, informations complémentaires et, en option, un périmètre
  (centre + rayon) placé sur la carte. Fiche zone : ses clients en cartes, sa carte, ajout groupé de clients,
  « Rattacher les clients du périmètre ». Supprimer une zone conserve ses clients (ils passent « sans zone »).
- **Carte** (menu Gestion → Carte, OpenStreetMap) : zones en cercles colorés, clients en marqueurs à la couleur de leur zone ;
  clic sur un marqueur → fiche résumée (solde dû, fiche complète, itinéraire) ; filtre par zone et recherche.
- **Position du client** : fiche client → « Enregistrer ma position chez le client » (GPS du téléphone ou du navigateur,
  après confirmation) ou clic sur la carte. Un client sans zone est rattaché automatiquement à la zone dont le périmètre contient sa position.
  Permission `clients.locate` (admin, gestionnaire, caissier) ; zones gérées avec `zones.manage` (admin, gestionnaire).
- **Filtre par zone** sur la liste des clients (combinable avec recherche, segment, statut, « avec solde dû », « localisés ») ;
  « Afficher tous les clients » retire tous les filtres.
- Le back-office présente les listes en **colonnes de cartes** (clients par zone / segment / statut, ventes par état de paiement,
  mouvements Entrées / Sorties, produits par opérateur, achats par état, utilisateurs par rôle) avec actions rapides (⋮).

## TVA facultative

- Activable par opération (ventes, achats, dépenses et recettes diverses) : interrupteur « Appliquer la TVA », taux libre
  ou raccourcis 7 / 13 / 19 %, prix saisis **TTC** ou **HT**. Paramètres → TVA : TVA proposée par défaut, taux par défaut, taux proposés.
- **Sans taux : aucun calcul**, le montant saisi est conservé tel quel. Avec un taux : HT, TVA et TTC sont calculés une seule fois
  (prix TTC → HT = TTC / (1 + taux) ; prix HT → TTC = HT × (1 + taux)), jamais de double TVA.
- `total` = TTC réellement dû/payé (soldes, caisse, créances) ; **chiffre d'affaires et marges en HT** ; coût d'achat mémorisé en HT.
- Statistiques, rapports PDF/WhatsApp et exports : CA HT, ventes TTC, **TVA collectée** (ventes + recettes), **TVA déductible**
  (achats + charges) et **TVA à reverser / crédit de TVA**.

## Modification et suppression des opérations

- **Ventes** : modifier (lignes, client, date, remise, TVA ; stock réajusté, encaissements conservés, trop-perçu remboursé
  automatiquement) ou supprimer (motif obligatoire ; stock restitué, encaissements supprimés). Permissions `sales.edit`, `sales.delete`.
- **Achats** : modifier (stock réajusté) ou supprimer (stock retiré, paiements supprimés).
- **Entrées / sorties** : modifier (montant, date, catégorie, mode, TVA, type de même sens) ou supprimer ; les ventes / achats liés
  sont recalculés. Permissions `transactions.edit`, `transactions.delete`.
- Confirmation avant chaque suppression ; toutes les modifications et suppressions sont tracées (valeurs avant / après, motif) dans le
  journal d'audit, et soldes, caisse, statistiques et rapports sont recalculés immédiatement.

## Règles métier clés

- **Vente ≠ encaissement.** Une vente fixe le chiffre d'affaires, le coût d'achat et le bénéfice brut ; l'argent reçu est un
  mouvement financier séparé (`transactions`, sens `in`), qui peut être partiel ou différé → créances clients.
- **Encaissement sans vente précisée** : imputé automatiquement sur les ventes impayées les plus anciennes (FIFO), le reste devient une avance.
- **Annulation** : stock restitué ; si la vente était encaissée, un remboursement (sortie) est enregistré.
- **Bénéfice net estimé** = bénéfice brut + autres recettes − (dépenses + frais + autres dépenses des catégories marquées « déduites du net »).
  Les paiements fournisseurs ne sont pas des charges (ils sont déjà dans le coût d'achat des produits vendus).
- **Remises globales** réparties au prorata des lignes (bénéfice par opérateur exact).
- **Frais de mode de paiement** (TPE, mobile…) : enregistrés automatiquement en sortie selon le taux du mode.
- **Caisse** : solde espèces = solde d'ouverture + entrées − sorties des modes « caisse ». La clôture journalière compare au
  montant compté ; l'écart peut être comptabilisé automatiquement.
- **Clients bénéficiaires / réguliers** : seuils configurables (bénéfice minimal, marge minimale, ventes par mois).
- **Opérateurs / produits / clients avec historique** : désactivés au lieu d'être supprimés.
- Tous les paramètres sont dans **Paramètres** (back-office), sans modification de code.

## Rôles

| Rôle | Accès |
|---|---|
| Administrateur | tout |
| Gestionnaire | tout sauf utilisateurs et paramètres |
| Caissier | ventes, encaissements, dépenses, clients, caisse — **uniquement ses propres opérations**, sans coûts ni marges |
| Consultation seule | lecture des tableaux de bord, statistiques, clients, ventes, rapports |

La matrice est dans `config/permissions.php` ; chaque permission est une Gate utilisée par le web et l'API.
Journal d'audit automatique (création / modification / suppression, exports, imports, envois) et historique des connexions.

## Architecture

```
app/
  Enums/            Role, TransactionType, ProductType
  Models/           Eloquent + concerns (Auditable, HasReference, OwnedByUser)
  Services/         SaleService, TransactionService, PurchaseService, CashService,
                    StatsService, ReportService, WhatsAppService, DataExchangeService
  Http/Requests/    validations partagées web + API
  Http/Controllers/Web       back-office Blade
  Http/Controllers/Api/V1    API mobile
  Http/Resources/   JSON de l'API (coûts masqués selon le rôle)
  Support/          Period (jour/semaine/mois/année/personnalisée), StatsScope, helpers
  Jobs/, Console/Commands/, Mail/, Exports/, Imports/
```

Toute la logique est dans `app/Services` : le web, l'API, les imports et le seed de démonstration passent par les mêmes
services — aucune règle métier dupliquée.

## API REST v1 (application mobile)

Authentification par jeton Sanctum (30 jours) : `Authorization: Bearer <token>`, `Accept: application/json`.

| Méthode | Route | Description |
|---|---|---|
| POST | `/api/v1/auth/login` | `{login, password, device_name}` → `{token, user{permissions}}` |
| GET / POST | `/api/v1/auth/me`, `/auth/logout` | profil, révocation du jeton |
| POST | `/api/v1/devices` | jeton push FCM/APNs `{token, platform}` |
| GET | `/api/v1/references` | opérateurs, produits, modes de paiement, catégories (cache hors ligne) |
| GET | `/api/v1/dashboard?period=day` | indicateurs, variations, solde de caisse, graphique 14 j |
| GET | `/api/v1/stats/summary`, `/stats/{operators,clients,products,expenses}` | statistiques filtrées (`period`, `date`, `start`, `end`, `client_id`, `operator_id`, `product_id`, `type`) |
| CRUD | `/api/v1/clients`, `/clients/{id}/profile`, `/sales`, `/transactions` | fiches et historiques |
| POST | `/api/v1/sales` | vente `{uuid, client_id, items[{product_id, quantity, unit_price?}], paid_amount, payment_method_id}` |
| POST | `/api/v1/sales/{id}/payments`, `/sales/{id}/cancel` | encaissement, annulation |
| POST | `/api/v1/transactions` | entrée / sortie `{uuid, type, amount, …}` |
| GET / POST | `/api/v1/reports`, `/reports/pdf`, `/reports/send` | rapport JSON + texte, PDF, envoi |
| GET / POST | `/api/v1/cash/day`, `/cash/close` | caisse du jour, clôture |
| GET | `/api/v1/clients?zone_id=<id>\|none&located=yes\|no` | filtre par zone et par localisation |
| PUT / DELETE | `/api/v1/clients/{id}/location` | position GPS `{latitude, longitude, accuracy}` (rattachement automatique à la zone) |
| GET / CRUD | `/api/v1/zones`, `/api/v1/zones/{id}` | zones (création / modification avec `zones.manage`) |
| GET | `/api/v1/map?zone_id=` | zones et clients localisés pour la carte |
| POST | `/api/v1/sync/push` | lot hors ligne `{clients[], sales[], transactions[]}` — idempotent par `uuid`, une vente peut référencer `client_uuid` |
| GET | `/api/v1/sync/pull?since=ISO8601` | modifications depuis la dernière synchronisation |

### Mode hors ligne (mobile)

1. L'app génère un UUID pour chaque client / vente / mouvement saisi et le stocke localement (SQLite / Hive).
2. À la reconnexion : `POST /sync/push` ; chaque élément renvoie `ok` (+ id serveur) ou `error` (+ messages).
   Renvoyer le même lot ne crée jamais de doublon.
3. Puis `GET /sync/pull?since=<server_time précédent>` pour rafraîchir le cache local.

## Import / export

Menu **Import / export** : export Excel / CSV des clients, produits, ventes, mouvements ; classeur statistique multi-feuilles ;
import Excel / CSV (clients, produits, ventes, mouvements) avec modèles téléchargeables et rapport d'erreurs ligne par ligne.
