docs: GUIDE + HANDOFF, docstrings app.py, fix syntax errors
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
# Guide — 3D Pricing App
|
||||
|
||||
Application web Flask/SQLite de gestion du pricing et de la planification pour un atelier d'impression 3D.
|
||||
|
||||
---
|
||||
|
||||
## Architecture technique
|
||||
|
||||
```
|
||||
Flask (Python) ──► SQLite (WAL mode)
|
||||
│
|
||||
├── Templates Jinja2 (Bootstrap 5 + vis.js)
|
||||
├── Thread arrière-plan : sync Home Assistant
|
||||
└── Docker : /data/pricing.db (persistant)
|
||||
```
|
||||
|
||||
**Stack :**
|
||||
- Python 3.12 + Flask
|
||||
- SQLite avec WAL (pas de blocage lecture/écriture simultanée)
|
||||
- Bootstrap 5 + Bootstrap Icons
|
||||
- vis.js Timeline (Gantt planning)
|
||||
- Authelia OIDC (optionnel, activé via variables d'env)
|
||||
- Home Assistant REST API (optionnel)
|
||||
- Nextcloud WebDAV (optionnel)
|
||||
|
||||
---
|
||||
|
||||
## Schéma de base de données
|
||||
|
||||
| Table | Rôle |
|
||||
|---|---|
|
||||
| `settings` | Clés/valeurs de configuration globale |
|
||||
| `clients` | Clients avec profils par défaut |
|
||||
| `projects` | Projets regroupant plusieurs commandes |
|
||||
| `jobs` | Commandes / calculs de prix (1 plateau = 1 job) |
|
||||
| `materials` | Filaments avec stock et historique de prix |
|
||||
| `material_price_history` | Historique des changements de prix filament |
|
||||
| `machine_profiles` | Profils machine (usure, électricité) |
|
||||
| `handling_profiles` | Profils manutention (taux horaire, minutes/plateau) |
|
||||
| `material_profiles` | Profils marge matière |
|
||||
| `pricing_profiles` | Profils multiplicateur design + marge brute |
|
||||
| `printers` | Imprimantes physiques avec préfixe HA |
|
||||
| `print_slots` | Créneaux d'impression planifiés |
|
||||
| `working_schedule` | Planning hebdomadaire (TT / sur site / off) |
|
||||
| `calendar_blocks` | Indisponibilités ponctuelles (plage de dates) |
|
||||
|
||||
---
|
||||
|
||||
## Moteur de calcul (`calc()`)
|
||||
|
||||
Tout se calcule **par pièce** à partir des données du plateau Bambu.
|
||||
|
||||
```
|
||||
Coût fixe = matière + marge_matière + usure_machine + électricité
|
||||
(divisé par pièces/plateau)
|
||||
|
||||
Sous-total = coût_fixe + manutention + design
|
||||
|
||||
Marge brute = sous-total × gross_margin_pct / 100
|
||||
|
||||
Total marge = manutention + design + marge_brute
|
||||
|
||||
Prix HT = coût_fixe + total_marge
|
||||
|
||||
Prix HT net = prix_ht / (1 - cotisations - VFL - autres_taxes)
|
||||
└─ les charges fiscales sont "self-contained" dans le prix
|
||||
|
||||
Prix TTC = prix_ht_net × (1 + TVA)
|
||||
|
||||
Prix final = prix_ttc × (1 - remise)
|
||||
```
|
||||
|
||||
**Multiplicateur design** : coefficient appliqué au coût matière pour valoriser le temps de modélisation. `×0.8` = design simple, `×1.8` = design complexe.
|
||||
|
||||
---
|
||||
|
||||
## Pages et fonctionnalités
|
||||
|
||||
### Dashboard (`/`)
|
||||
Vue d'ensemble : 10 dernières commandes, CA total, CA du mois, alertes stock bas.
|
||||
|
||||
### Commandes (`/jobs`)
|
||||
Liste de toutes les commandes avec réf. plateau, poids, durée, marge, remise, prix final.
|
||||
|
||||
- **Nouveau job** : saisie manuelle ou import `.gcode.3mf` depuis Nextcloud
|
||||
- **Import Bambu** : parse `slice_info.config` → détecte les plateaux, poids, durée, filaments
|
||||
- **Duplication** (`?clone_from=ID`) : copie les paramètres + re-parse automatiquement le fichier Nextcloud si `source_nc_path` est renseigné
|
||||
- **Export CSV** : toutes les commandes en CSV
|
||||
|
||||
### Détail commande (`/jobs/<id>`)
|
||||
- Décomposition du prix (coût fixe, variable, fiscal)
|
||||
- Section **Plateaux d'impression** : liste des slots avec statut, pièces, avancement HA
|
||||
- Portail client : génération d'un lien de partage tokenisé
|
||||
|
||||
### Projets (`/projects`)
|
||||
Regroupe plusieurs commandes sous un même projet client. Affiche total pièces et CA.
|
||||
|
||||
### Clients (`/clients`)
|
||||
Clients avec profils par défaut (machine, manutention, matière, tarif). Ces profils se chargent automatiquement à la création d'un job pour ce client.
|
||||
|
||||
### Matières (`/materials`)
|
||||
- Stock en grammes avec alerte seuil bas
|
||||
- Historique des prix
|
||||
- Déduction automatique du stock à la création d'un job
|
||||
- Suivi du gaspillage (impressions ratées)
|
||||
|
||||
### Profils (`/profiles`)
|
||||
4 types de profils réutilisables :
|
||||
- **Machine** : prix imprimante, durée de vie, nozzle, plateau, puissance, électricité
|
||||
- **Manutention** : taux horaire, minutes par plateau
|
||||
- **Matière** : marge matière en %
|
||||
- **Tarif** : multiplicateur design + marge brute
|
||||
|
||||
### Planning (`/planning`)
|
||||
Gantt vis.js sur 14 jours (démarre 12h avant maintenant pour voir les impressions en cours).
|
||||
|
||||
- **Gantt** : slots par imprimante, codes couleur par statut, bandes rouges si capacité saturée
|
||||
- **À planifier** : jobs dont tous les plateaux ne sont pas encore planifiés
|
||||
- **Overlay HA live** : rafraîchissement automatique (intervalle configurable) des statuts depuis Home Assistant
|
||||
- **Badges compensation** : si HA signale des pièces ignorées sur un plateau, les autres plateaux du même job proposent d'augmenter leur quantité
|
||||
|
||||
**Planifier un slot :**
|
||||
1. Cliquer sur un job "À planifier"
|
||||
2. Choisir imprimante + date/heure de lancement
|
||||
3. Option "Déjà imprimé" pour enregistrer rétroactivement sans vérification de capacité
|
||||
|
||||
**Statuts des slots :**
|
||||
| Statut | Couleur | Signification |
|
||||
|---|---|---|
|
||||
| `planned` | bleu | Planifié, pas encore lancé |
|
||||
| `running` | orange | En cours (mis à jour par HA sync) |
|
||||
| `done` | vert | Terminé |
|
||||
| `failed` | rouge | Raté (gaspillage logué) |
|
||||
| `cancelled` | gris | Annulé |
|
||||
|
||||
### Imprimantes (`/printers`)
|
||||
- Activer/désactiver des imprimantes
|
||||
- Configurer le préfixe HA (`a1_1` → surveille `sensor.a1_1_etat_de_l_impression`)
|
||||
- Modifier nom, préfixe HA, notes
|
||||
|
||||
### Planning horaire (`/working-schedule`)
|
||||
Configuré par jour de la semaine :
|
||||
- **TT** (télétravail) : fenêtre horaire avec nb de lancements calculé automatiquement
|
||||
- **Onsite** : 2 créneaux fixes (ex: 07h00 + 18h30)
|
||||
- **Off** : aucun lancement possible
|
||||
|
||||
### Indisponibilités (`/calendar-blocks`)
|
||||
Bloquer une période (date début → date fin optionnelle) pour une ou toutes les imprimantes.
|
||||
Types : Off / Télétravail / Sur site / Maintenance machine.
|
||||
|
||||
### Page mobile (`/mobile`)
|
||||
Interface simplifiée pour saisie rapide sur smartphone :
|
||||
- Ajouter une indisponibilité
|
||||
- Décaler un créneau
|
||||
- Marquer une impression comme ratée ou terminée
|
||||
|
||||
### Statistiques (`/stats`)
|
||||
CA par période, matières les plus utilisées, gaspillage, top clients.
|
||||
|
||||
### Paramètres (`/settings`)
|
||||
- Taux fiscaux (cotisations, VFL, TVA, autres taxes)
|
||||
- Paramètres machine par défaut
|
||||
- Configuration Nextcloud (URL, user, mot de passe d'app, dossier racine)
|
||||
- Configuration Home Assistant (URL, token, intervalle de sync)
|
||||
- Nombre max d'imprimantes simultanées
|
||||
- Cooldown entre impressions (minutes)
|
||||
|
||||
---
|
||||
|
||||
## Home Assistant Sync
|
||||
|
||||
Le thread HA tourne en arrière-plan et poll toutes les N secondes (configurable, défaut 60s).
|
||||
|
||||
**Entités surveillées** (par imprimante avec préfixe `{prefix}`) :
|
||||
- `sensor.{prefix}_etat_de_l_impression` → `running` / `finish` / `unknown`
|
||||
- `binary_sensor.{prefix}_erreur_d_impression` → `on` / `off`
|
||||
- `sensor.{prefix}_objets_ignores` → nombre de pièces ignorées (compensation multi-plateau)
|
||||
- `sensor.{prefix}_avancement_de_l_impression` → % d'avancement
|
||||
|
||||
**Logique de sync :**
|
||||
1. Cherche un slot `planned` ou `running` qui chevauche la fenêtre actuelle (±30 min)
|
||||
2. `running` → passe le slot à `running`
|
||||
3. `finish` → passe le slot à `done`
|
||||
4. `binary_sensor erreur = on` → passe le slot à `failed`
|
||||
5. `objets_ignores > 0` → met à jour `pieces_ignored` sur le slot
|
||||
|
||||
**Important** : le sync utilise des connexions courtes par imprimante (autocommit) pour ne pas bloquer les requêtes Flask.
|
||||
|
||||
---
|
||||
|
||||
## Nextcloud
|
||||
|
||||
Utilisé comme bibliothèque de fichiers `.gcode.3mf`.
|
||||
|
||||
- Navigation WebDAV via le picker modal dans "Nouveau job"
|
||||
- Téléchargement + parsing du `.3mf` côté serveur (`/api/nextcloud/parse`)
|
||||
- Chemin stocké dans `source_nc_path` pour permettre la duplication sans re-sélection
|
||||
|
||||
---
|
||||
|
||||
## Portail client
|
||||
|
||||
Chaque commande peut générer un lien tokenisé (`/portal/<token>`) donnant accès à :
|
||||
- Décomposition du prix en lecture seule
|
||||
- Sans authentification requise
|
||||
|
||||
---
|
||||
|
||||
## Variables d'environnement (Docker)
|
||||
|
||||
| Variable | Défaut | Rôle |
|
||||
|---|---|---|
|
||||
| `SECRET_KEY` | généré aléatoirement | Clé session Flask |
|
||||
| `DATABASE_PATH` | `/data/pricing.db` | Chemin SQLite |
|
||||
| `OIDC_CLIENT_ID` | — | Active l'auth OIDC si défini |
|
||||
| `OIDC_CLIENT_SECRET` | — | Secret OIDC |
|
||||
| `OIDC_DISCOVERY_URL` | — | URL metadata OIDC (Authelia) |
|
||||
| `OIDC_END_SESSION_URL` | — | URL déconnexion OIDC |
|
||||
|
||||
---
|
||||
|
||||
## Calendrier iCal (`/calendar.ics`)
|
||||
|
||||
Export iCal des créneaux planifiés. Protégé par token (`ical_token` dans settings).
|
||||
URL : `http://host/calendar.ics?token=<ical_token>`
|
||||
|
||||
---
|
||||
|
||||
## API JSON principales
|
||||
|
||||
| Endpoint | Méthode | Rôle |
|
||||
|---|---|---|
|
||||
| `/api/calculate` | POST | Calcul de prix live (formulaire new_job) |
|
||||
| `/api/slots` | GET | Liste des slots pour le Gantt (7 derniers jours → +) |
|
||||
| `/api/slots/new` | POST | Créer un slot planifié |
|
||||
| `/api/slots/<id>/move` | POST | Déplacer un slot |
|
||||
| `/api/slots/<id>/fail` | POST | Marquer comme raté |
|
||||
| `/api/slots/<id>/done` | POST | Marquer comme terminé |
|
||||
| `/api/slots/<id>/status` | POST | Changer le statut |
|
||||
| `/api/slots/<id>/pieces_override` | POST | Override nb pièces (compensation) |
|
||||
| `/api/suggest-slot` | POST | Suggérer le prochain créneau libre |
|
||||
| `/api/capacity` | POST | Calculer la capacité de production |
|
||||
| `/api/ha/status` | GET | Statuts HA de toutes les imprimantes |
|
||||
| `/api/parse-3mf` | POST | Parser un fichier .3mf uploadé |
|
||||
| `/api/nextcloud/browse` | GET | Lister un dossier Nextcloud |
|
||||
| `/api/nextcloud/parse` | GET | Fetch + parser un .3mf Nextcloud |
|
||||
| `/api/nextcloud/file` | GET | Proxy téléchargement fichier Nextcloud |
|
||||
| `/api/client/<id>/defaults` | GET | Profils par défaut d'un client |
|
||||
Reference in New Issue
Block a user