Files
ske087 bff6d70b17 Initial commit: aplicatie de cantarire si etichetare
Aplicatie Flask + SQLite pentru productie alimentara: cantarirea
componentelor unui produs finit si tiparirea etichetei prin QZ Tray.

- produse finite (retete) formate din componente cantarite
- designer vizual de etichete (mm/px, zona sigura, campuri variabile,
  cod QR cu continut din mai multe bucati)
- legare produs finit -> sablon de eticheta
- navigare pe doua taburi: Cantarire / Setari
- administrare: componente, produse finite, sabloane, campuri, istoric
- backup, resetare baza de date, checklist de pregatire, /healthz
- CLI de administrare si serviciu systemd pentru productie
- vendor/syncpulse-scale-bridge (GPL-3.0-or-later) pentru citirea cantarului
2026-10-18 23:38:45 +03:00

177 lines
6.8 KiB
Markdown

# Punere în funcțiune
Ghid pas cu pas pentru o stație de producție (cântar + imprimantă de etichete).
Aplicația rulează local, fără servicii externe: Flask + SQLite, fișierele stau în `instance/`.
## 1. Cerințe pe stație
| Ce | Detaliu |
|---|---|
| Python | 3.10+ (testat pe 3.13) |
| Cântar | Bizerba BC800 pe RJ11/10P4C → adaptor USB-serial (apare ca `COMx`) |
| Imprimantă | termică de etichete, separată de cântar |
| QZ Tray | 2.2.x instalat și pornit (`localhost:8181`) pentru tipărire directă |
| Rețea | nu e nevoie de internet; doar rețeaua locală dacă vrei acces din alt PC |
## 2. Instalare
```bash
git clone <repo> cantarire-etichetare
cd cantarire-etichetare
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
```
Configurare (recomandat): copiază `.env.example` în `.env` și completează cel puțin cheia:
```bash
python -c "import secrets; print(secrets.token_urlsafe(48))"
```
## 3. Prima pornire
```bash
python run.py
```
La prima rulare se creează automat `instance/cantarire.db`, cu schema completă, setările
implicite și un șablon de etichetă. Sumarul din consolă arată calea bazei și ce mai lipsește:
```
Cantarire & etichetare - server flask
URL http://127.0.0.1:5000/
Baza /.../instance/cantarire.db (64.0 kB, schema v5)
Date 0 componente / 0 produse finite / 1 sabloane
De completat: Datele firmei, Componente, Produse finite (lista apare pe pagina principală)
```
Pagina **Cântărire** afișează un checklist până când totul e pregătit. Ordinea firească:
1. **Setări → Date firmă** — denumirea care apare pe etichetă, telefon.
2. **Setări → Componente** — ce se cântărește (Fasole, Carne, ...).
3. **Setări → Produse finite** — denumirea de pe etichetă + componentele în ordinea cântăririi,
opțional șablonul de etichetă propriu.
4. **Setări → Șabloane** — dacă vrei alt design decât cel implicit (designer vizual).
5. **Setări → Câmpuri** — opțional, texte reutilizabile pentru etichete.
6. **Setări → Cântar** — alege profilul activ din `instance/bridge.json`.
Verificare rapidă, din consolă:
```bash
python -m cantarire.tools.admin status
python -m cantarire.tools.admin check
```
`check` întoarce cod 0 doar când elementele obligatorii sunt completate (util în scripturi).
## 4. Cântarul
Profilul serial stă în `instance/bridge.json`. Dacă nu ai încă unul:
```bash
python -m cantarire.tools.monitor --list
python -m cantarire.tools.monitor COM7 --baud 9600
```
Monitorul doar ascultă (nu scrie pe port), decodează cadrele cunoscute și poate salva o captură
pentru analiză. Când ai o captură, profilul se adaugă în `bridge.json` (sau din
**Setări → Monitor serial**). Pentru teste fără hardware:
```bash
CANTARIRE_SIMULATE=mahak_mds python run.py
```
Fără profil activ aplicația funcționează normal, cu introducere manuală a greutății.
## 5. Imprimanta (QZ Tray)
1. Instalează QZ Tray pe stație și pornește-l.
2. Deschide aplicația: pastila **QZ Tray** din dreapta sus trebuie să devină verde.
3. **Setări → Imprimantă implicită** → alege imprimanta termică.
4. **Tipărește test** — trebuie să iasă o etichetă demo.
Dacă QZ nu răspunde, aplicația cade automat pe tipărirea din browser (fereastră de print),
deci eticheta iese oricum.
## 6. Producție
```bash
python run.py --production # waitress, 0.0.0.0:5000
python run.py --production --port 8080
```
Serverul de dezvoltare Flask nu se folosește în producție. `--production` pornește
**waitress** (WSGI, 8 fire) și afișează un avertisment dacă `CANTARIRE_SECRET_KEY` lipsește.
### Linux (systemd)
```bash
sudo useradd -r -s /usr/sbin/nologin cantarire
sudo mkdir -p /opt/cantarire-etichetare /var/lib/cantarire
sudo chown -R cantarire:cantarire /opt/cantarire-etichetare /var/lib/cantarire
# copiază proiectul în /opt/cantarire-etichetare, apoi:
sudo cp deploy/cantarire.service /etc/systemd/system/
sudo systemctl edit --full cantarire # verifică utilizatorul și calea
sudo systemctl enable --now cantarire
```
`EnvironmentFile=-/etc/cantarire.env` conține variabilele din `.env.example`; fișierul e opțional.
Serviciul rulează cu `ProtectSystem=full` și scrie doar în `/var/lib/cantarire`.
### Windows (stația de producție)
Rulează `deploy\start-windows.bat`. Scriptul creează `.venv` dacă lipsește, generează o cheie de
sesiune în `instance\secret.key` (refolosită la următoarele porniri) și pornește serverul.
Pentru pornire automată: creează un shortcut către acel `.bat` în
`shell:startup` (Win+R → `shell:startup`).
## 7. Backup și reset
```bash
python -m cantarire.tools.admin backup # instance/backups/cantarire-<data>.db
python -m cantarire.tools.admin backup --keep 30 # păstrează ultimele 30
python -m cantarire.tools.admin reset --yes # golește datele (face backup automat)
python -m cantarire.tools.admin seed-demo # repune datele demo pentru instruire
```
Backup-ul folosește API-ul SQLite (consistent și cu WAL activ), nu o simplă copiere de fișier.
Din interfață: **Setări → Descarcă backup** produce un backup proaspăt și îl descarcă.
`reset` șterge componente, produse finite, pachete, șabloane și câmpuri, readuce setările
implicite și recreează șablonul de etichetă standard — exact starea de după o instalare nouă.
## 8. Monitorizare
| Endpoint | Rol |
|---|---|
| `GET /healthz` | JSON cu starea bazei (integritate, schema, număr de înregistrări) și `setup.ready`; `503` dacă baza e inaccesibilă |
| `GET /setari` | cardul **Sistem**: cale, mărime, integritate, backup-uri |
Jurnalele ajung la stdout (systemd: `journalctl -u cantarire -f`). Polling-ul greutății
(`/api/weight`) este filtrat din jurnal ca să nu umple discul.
## 9. Actualizare
```bash
python -m cantarire.tools.admin backup
git pull
pip install -r requirements.txt
sudo systemctl restart cantarire # Windows: închide și redeschide start-windows.bat
```
Migrările de schemă rulează automat la pornire (v1 → v5); coloanele noi se adaugă fără pierdere
de date. Rulează `check` după actualizare.
## 10. Dacă ceva nu merge
| Simptom | Cauză probabilă |
|---|---|
| Lista de pornire nu dispare | lipsește un produs finit **cu componente** active |
| Pastila QZ e roșie | agentul QZ Tray nu e pornit; pornește-l și apasă **Conectează** |
| Greutatea nu se mișcă | profil greșit sau port ocupat — verifică în **Monitor serial** |
| `Database is locked` | două instanțe pe aceeași bază; oprește serviciul vechi |
| Eticheta iese goală | produsul finit e legat de un șablon șters — verifică **Șabloane** și resetează designul |
| `503` la `/healthz` | baza e coruptă sau fără drepturi de scriere; restaurează ultimul backup |