Compare commits
10
Commits
37801fca2a
...
263aefe9fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
263aefe9fc
|
||
|
|
07666b30c9
|
||
|
|
65dd976bb4
|
||
|
|
0fb573552d
|
||
|
|
23c4c7ded0
|
||
|
|
c30d4cb34a
|
||
|
|
18b4199d0a
|
||
|
|
1a93fc739d
|
||
|
|
550750fe88
|
||
|
|
23173e79b2
|
@@ -0,0 +1,6 @@
|
|||||||
|
FROM python:3.12-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
COPY server.py receipt.py ./
|
||||||
|
CMD ["python", "server.py"]
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
qrcode
|
||||||
|
pillow
|
||||||
+380
-519
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
PID_FILE="$SCRIPT_DIR/data/server.pid"
|
PID_FILE="$SCRIPT_DIR/data/server.pid"
|
||||||
PORT=8989
|
PORT=4566
|
||||||
|
|
||||||
# Proveri da li server već radi
|
# Proveri da li server već radi
|
||||||
check_running() {
|
check_running() {
|
||||||
|
|||||||
@@ -38,9 +38,19 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
- Security HTTP headers (CSP, X-Frame-Options, Referrer-Policy, nosniff...)
|
- Security HTTP headers (CSP, X-Frame-Options, Referrer-Policy, nosniff...)
|
||||||
- Login attempt logging — history by user, IP, reason, date
|
- Login attempt logging — history by user, IP, reason, date
|
||||||
- Users and roles — admin panel, user management
|
- Users and roles — admin panel, user management
|
||||||
- Inventory — items, categories, filtering, critical stock levels
|
- Inventory — items, categories, filtering, critical stock levels, per-item stock card, supplier links, item transfers
|
||||||
- Service orders — intake, status bar, costs, receipt
|
- Service orders:
|
||||||
|
- Intake form, status bar, archive
|
||||||
|
- Diagnostic workflow — fault description, technician notes, work done, diagnostic fee
|
||||||
|
- Parts and services — used items deducted from stock; suggested items (proposal to client)
|
||||||
|
- Client proposal approval — client receives a public link (QR code) to accept or reject a parts/service proposal with a comment
|
||||||
|
- Public status page — client can check order status and receive notifications via a unique link
|
||||||
|
- Documents — work order, pre-invoice (estimate), dispatch note, return slip, device label (QR + Code128 barcode)
|
||||||
|
- Pickup with payment — tracks payment method and advance amount
|
||||||
|
- Guarantee period, expected completion date, technician assignment, client notes
|
||||||
- Sales orders — items, calculation, receipt with company and client details
|
- Sales orders — items, calculation, receipt with company and client details
|
||||||
|
- Services catalog — service price list used for billing in service orders
|
||||||
|
- Expenses — expense records with category and amount
|
||||||
- Procurement — records of purchases from suppliers
|
- Procurement — records of purchases from suppliers
|
||||||
- Sales price calculation on procurement — markup (global, per category, per item), landed costs (customs, shipping...) allocated across items, two-way markup↔price computation; respects VAT-payer status
|
- Sales price calculation on procurement — markup (global, per category, per item), landed costs (customs, shipping...) allocated across items, two-way markup↔price computation; respects VAT-payer status
|
||||||
- Price revaluation (nivelacija) — sales price changes with an audit trail (old→new, reason, source, user)
|
- Price revaluation (nivelacija) — sales price changes with an audit trail (old→new, reason, source, user)
|
||||||
@@ -50,7 +60,7 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
- VAT rate code list
|
- VAT rate code list
|
||||||
- Clients and suppliers — contact database
|
- Clients and suppliers — contact database
|
||||||
- Reminders — records with deadlines
|
- Reminders — records with deadlines
|
||||||
- Reports — revenue overview, inventory status
|
- Reports — revenue overview, inventory status, inventory value report, stock movement list, stocktake (physical count)
|
||||||
- Settings — company name, address, Tax ID (PIB), logo; theme toggle
|
- Settings — company name, address, Tax ID (PIB), logo; theme toggle
|
||||||
- Background images — login page and app, with blur, transparency and glass effect
|
- Background images — login page and app, with blur, transparency and glass effect
|
||||||
- Personal theme and background — each user can set their own theme and background image
|
- Personal theme and background — each user can set their own theme and background image
|
||||||
@@ -62,9 +72,12 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
- Automated tests — unit and integration over a SQLite database (crypto, RBAC, login flows, form validators, reports)
|
- Automated tests — unit and integration over a SQLite database (crypto, RBAC, login flows, form validators, reports)
|
||||||
- **Demo mode** (`NTECH_ENV=demo`) — auto-created demo user, pre-filled login form, restricted backup count, blocked password/2FA changes
|
- **Demo mode** (`NTECH_ENV=demo`) — auto-created demo user, pre-filled login form, restricted backup count, blocked password/2FA changes
|
||||||
|
|
||||||
|
### In Progress
|
||||||
|
|
||||||
|
- **Fiscalization (ESIR/PFR)** — Teron L-PFR mock server included in `Fisk/`; Go client integration planned
|
||||||
|
|
||||||
### Planned
|
### Planned
|
||||||
|
|
||||||
- Fiscalization (ESIR/PFR)
|
|
||||||
- KPO book and double-entry bookkeeping (optional, later phase)
|
- KPO book and double-entry bookkeeping (optional, later phase)
|
||||||
- PostgreSQL support (for multi-user environments)
|
- PostgreSQL support (for multi-user environments)
|
||||||
- WebAuthn / Passkey login (database schema is already prepared)
|
- WebAuthn / Passkey login (database schema is already prepared)
|
||||||
@@ -80,6 +93,7 @@ The goal is simple: everything the repair shop needs to track is located in one
|
|||||||
| [Go](https://go.dev) | backend language |
|
| [Go](https://go.dev) | backend language |
|
||||||
| [chi](https://github.com/go-chi/chi) | HTTP router |
|
| [chi](https://github.com/go-chi/chi) | HTTP router |
|
||||||
| [html/template](https://pkg.go.dev/html/template) | server-side templates |
|
| [html/template](https://pkg.go.dev/html/template) | server-side templates |
|
||||||
|
| [HTMX](https://htmx.org) | dynamic HTML over HTTP |
|
||||||
| [Alpine.js](https://alpinejs.dev) | client-side UI logic |
|
| [Alpine.js](https://alpinejs.dev) | client-side UI logic |
|
||||||
| [SQLite](https://sqlite.org) + [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | main database (pure Go, no CGO) |
|
| [SQLite](https://sqlite.org) + [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | main database (pure Go, no CGO) |
|
||||||
| [PostgreSQL](https://www.postgresql.org) + [pgx/v5](https://github.com/jackc/pgx) | optional production database |
|
| [PostgreSQL](https://www.postgresql.org) + [pgx/v5](https://github.com/jackc/pgx) | optional production database |
|
||||||
@@ -188,6 +202,78 @@ your.domain.com {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### With Teron L-PFR Mock (Fiscalization Testing)
|
||||||
|
|
||||||
|
The `Fisk/` directory contains a Python mock server that simulates a [Teron](https://teron.rs) L-PFR fiscal device (port 4566). It implements the Teron HTTP API — invoice signing, PDV calculation, QR code generation, and per-type counters — without requiring real hardware or a certificate.
|
||||||
|
|
||||||
|
Use it alongside NTech for fiscalization development and testing:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
services:
|
||||||
|
ntech:
|
||||||
|
image: ghcr.io/dalibor31/ntech:latest
|
||||||
|
container_name: ntech
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
NTECH_ENV: production
|
||||||
|
NTECH_PORT: "8000"
|
||||||
|
NTECH_SQLITE: /app/data/ntech.db
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data
|
||||||
|
- ./uploads:/app/web/static/uploads
|
||||||
|
- ./logs:/var/log/ntech
|
||||||
|
- ./backups:/app/backups
|
||||||
|
networks:
|
||||||
|
- ntech-net
|
||||||
|
|
||||||
|
teron-mock:
|
||||||
|
image: ghcr.io/dalibor31/ntech-fisk:latest
|
||||||
|
container_name: teron_mock
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- teron-data:/app/data
|
||||||
|
networks:
|
||||||
|
- ntech-net
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
teron-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ntech-net:
|
||||||
|
```
|
||||||
|
|
||||||
|
The `teron-mock` service is reachable from `ntech` at `http://teron-mock:4566` over the internal Docker network — the port is not exposed to the host.
|
||||||
|
|
||||||
|
To run the mock server locally (without Docker):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd Fisk
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python server.py
|
||||||
|
# or: ./start.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Teron Mock Endpoints
|
||||||
|
|
||||||
|
| Method | Path | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| GET | `/api/status` | Device status and last invoice number |
|
||||||
|
| GET | `/api/attention` | Active alerts |
|
||||||
|
| POST | `/api/pin` | PIN verification (BE unlock) |
|
||||||
|
| GET | `/api/settings` | Device settings |
|
||||||
|
| POST | `/api/invoices` | Issue a fiscal invoice |
|
||||||
|
| POST | `/api/invoices/final` | Finalize an advance invoice |
|
||||||
|
| GET | `/api/invoices/last` | Last issued invoice |
|
||||||
|
| GET | `/api/invoices/:invoiceNumber` | Invoice by number |
|
||||||
|
| POST | `/api/invoices/search` | Search invoices |
|
||||||
|
|
||||||
|
Counters, signed receipts, QR codes, and JSON invoice data are persisted in `Fisk/data/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Demo Mode
|
### Demo Mode
|
||||||
|
|
||||||
Demo mode runs a fully functional copy with a pre-created `Demo` / `Demo1234` admin account. Password and 2FA changes are blocked. Backup is limited to 2 copies.
|
Demo mode runs a fully functional copy with a pre-created `Demo` / `Demo1234` admin account. Password and 2FA changes are blocked. Backup is limited to 2 copies.
|
||||||
|
|||||||
+90
-4
@@ -38,9 +38,19 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
- Bezbednosni HTTP headeri (CSP, X-Frame-Options, Referrer-Policy, nosniff...)
|
- Bezbednosni HTTP headeri (CSP, X-Frame-Options, Referrer-Policy, nosniff...)
|
||||||
- Evidencija pokušaja prijave — istorija po korisniku, IP, razlog, datum
|
- Evidencija pokušaja prijave — istorija po korisniku, IP, razlog, datum
|
||||||
- Korisnici i uloge — admin panel, upravljanje korisnicima
|
- Korisnici i uloge — admin panel, upravljanje korisnicima
|
||||||
- Magacin — artikli, kategorije, filtriranje, kritični nivoi zaliha
|
- Magacin — artikli, kategorije, filtriranje, kritični nivoi zaliha, magacinska kartica po artiklu, veza sa dobavljačima, premeštanje artikala
|
||||||
- Servisni nalozi — prijem, statusna traka, troškovi, priznanica
|
- Servisni nalozi:
|
||||||
|
- Forma prijema, statusna traka, arhiva
|
||||||
|
- Tok dijagnostike — opis kvara, napomene servisera, urađeno, cena dijagnostike
|
||||||
|
- Delovi i radovi — ugrađeni artikli se skidaju sa lagera; predloženi artikli (ponuda klijentu)
|
||||||
|
- Odobravanje predloga — klijent dobija javni link (QR kod) da prihvati ili odbije predlog sa komentarom
|
||||||
|
- Javna statusna stranica — klijent prati status naloga putem jedinstvenog linka
|
||||||
|
- Dokumenti — radni nalog, predračun, otpremnica, revers, nalepnica za uređaj (QR + Code128 barkod)
|
||||||
|
- Preuzimanje sa naplatom — način plaćanja i iznos avansa
|
||||||
|
- Garancija, predviđen datum završetka, serviser, napomena klijentu
|
||||||
- Prodajni nalozi — stavke, obračun, priznanica sa podacima firme i klijenta
|
- Prodajni nalozi — stavke, obračun, priznanica sa podacima firme i klijenta
|
||||||
|
- Cenovnik usluga — šifarnik usluga za obračun u servisnim nalozima
|
||||||
|
- Troškovi — evidencija troškova po kategoriji i iznosu
|
||||||
- Nabavke — evidencija nabavki od dobavljača
|
- Nabavke — evidencija nabavki od dobavljača
|
||||||
- Kalkulacija prodajne cene pri nabavci — marža (globalna, po kategoriji i po artiklu), zavisni troškovi (carina, prevoz...) sa raspodelom na stavke, dvosmerni izračun marža↔prodajna; poštuje status PDV obveznika
|
- Kalkulacija prodajne cene pri nabavci — marža (globalna, po kategoriji i po artiklu), zavisni troškovi (carina, prevoz...) sa raspodelom na stavke, dvosmerni izračun marža↔prodajna; poštuje status PDV obveznika
|
||||||
- Nivelacija — promena prodajne cene uz trag (istorija promena: stara→nova, razlog, izvor, korisnik)
|
- Nivelacija — promena prodajne cene uz trag (istorija promena: stara→nova, razlog, izvor, korisnik)
|
||||||
@@ -50,7 +60,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
- Šifarnik PDV stopa
|
- Šifarnik PDV stopa
|
||||||
- Klijenti i dobavljači — baza kontakata
|
- Klijenti i dobavljači — baza kontakata
|
||||||
- Podsetnici — evidencija sa rokom
|
- Podsetnici — evidencija sa rokom
|
||||||
- Izveštaji — pregled prihoda, stanje magacina
|
- Izveštaji — pregled prihoda, stanje magacina, vrednost zaliha, prometni list, popis (inventura)
|
||||||
- Podešavanja — naziv, adresa, PIB, logo firme; promena teme
|
- Podešavanja — naziv, adresa, PIB, logo firme; promena teme
|
||||||
- Pozadinske slike — login stranica i aplikacija, sa zamućenjem, providnošću i glass efektom
|
- Pozadinske slike — login stranica i aplikacija, sa zamućenjem, providnošću i glass efektom
|
||||||
- Lična tema i pozadina — svaki korisnik može svoju temu i pozadinsku sliku
|
- Lična tema i pozadina — svaki korisnik može svoju temu i pozadinsku sliku
|
||||||
@@ -62,9 +72,12 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
- Automatski testovi — jedinični i integracioni nad SQLite bazom (kripto, RBAC, tokovi prijave, validatori forme, izveštaji)
|
- Automatski testovi — jedinični i integracioni nad SQLite bazom (kripto, RBAC, tokovi prijave, validatori forme, izveštaji)
|
||||||
- **Demo mod** (`NTECH_ENV=demo`) — automatski kreiran demo korisnik, pre-popunjeni login, ograničen bekap, blokirana promena lozinke i 2FA
|
- **Demo mod** (`NTECH_ENV=demo`) — automatski kreiran demo korisnik, pre-popunjeni login, ograničen bekap, blokirana promena lozinke i 2FA
|
||||||
|
|
||||||
|
### U toku
|
||||||
|
|
||||||
|
- **Fiskalizacija (ESIR/PFR)** — Teron L-PFR mock server dostupan u `Fisk/`; integracija Go klijenta u planu
|
||||||
|
|
||||||
### Planirano
|
### Planirano
|
||||||
|
|
||||||
- Fiskalizacija (ESIR/PFR)
|
|
||||||
- KPO knjiga i dvojno knjigovodstvo (opciono, kasnija faza)
|
- KPO knjiga i dvojno knjigovodstvo (opciono, kasnija faza)
|
||||||
- Podrška za PostgreSQL (za višekorisničko okruženje)
|
- Podrška za PostgreSQL (za višekorisničko okruženje)
|
||||||
- WebAuthn / Passkey prijava (šema baze je pripremljena)
|
- WebAuthn / Passkey prijava (šema baze je pripremljena)
|
||||||
@@ -80,6 +93,7 @@ Cilj je jednostavan: sve što servis treba da prati nalazi se na jednom mestu, b
|
|||||||
| [Go](https://go.dev) | backend jezik |
|
| [Go](https://go.dev) | backend jezik |
|
||||||
| [chi](https://github.com/go-chi/chi) | HTTP ruter |
|
| [chi](https://github.com/go-chi/chi) | HTTP ruter |
|
||||||
| [html/template](https://pkg.go.dev/html/template) | serverski šabloni |
|
| [html/template](https://pkg.go.dev/html/template) | serverski šabloni |
|
||||||
|
| [HTMX](https://htmx.org) | dinamički HTML preko HTTP-a |
|
||||||
| [Alpine.js](https://alpinejs.dev) | UI logika na strani klijenta |
|
| [Alpine.js](https://alpinejs.dev) | UI logika na strani klijenta |
|
||||||
| [SQLite](https://sqlite.org) + [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | glavna baza (čisti Go, bez CGO) |
|
| [SQLite](https://sqlite.org) + [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | glavna baza (čisti Go, bez CGO) |
|
||||||
| [PostgreSQL](https://www.postgresql.org) + [pgx/v5](https://github.com/jackc/pgx) | opciona baza za produkciju |
|
| [PostgreSQL](https://www.postgresql.org) + [pgx/v5](https://github.com/jackc/pgx) | opciona baza za produkciju |
|
||||||
@@ -188,6 +202,78 @@ tvoj.domen.com {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Sa Teron L-PFR mokom (testiranje fiskalizacije)
|
||||||
|
|
||||||
|
Folder `Fisk/` sadrži Python mock server koji simulira [Teron](https://teron.rs) L-PFR fiskalni uređaj (port 4566). Implementira Teron HTTP API — potpisivanje računa, PDV obračun, generisanje QR koda i brojače po tipu računa — bez potrebe za pravim hardverom ili sertifikatom.
|
||||||
|
|
||||||
|
Koristi se uz NTech za razvoj i testiranje fiskalizacije:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
services:
|
||||||
|
ntech:
|
||||||
|
image: ghcr.io/dalibor31/ntech:latest
|
||||||
|
container_name: ntech
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
NTECH_ENV: production
|
||||||
|
NTECH_PORT: "8000"
|
||||||
|
NTECH_SQLITE: /app/data/ntech.db
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data
|
||||||
|
- ./uploads:/app/web/static/uploads
|
||||||
|
- ./logs:/var/log/ntech
|
||||||
|
- ./backups:/app/backups
|
||||||
|
networks:
|
||||||
|
- ntech-net
|
||||||
|
|
||||||
|
teron-mock:
|
||||||
|
image: ghcr.io/dalibor31/ntech-fisk:latest
|
||||||
|
container_name: teron_mock
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- teron-data:/app/data
|
||||||
|
networks:
|
||||||
|
- ntech-net
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
teron-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ntech-net:
|
||||||
|
```
|
||||||
|
|
||||||
|
Servis `teron-mock` je dostupan iz `ntech` kontejnera na adresi `http://teron-mock:4566` preko interne Docker mreže — port nije izložen spolja.
|
||||||
|
|
||||||
|
Za lokalno pokretanje moka (bez Dockera):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd Fisk
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python server.py
|
||||||
|
# ili: ./start.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Teron Mock endpointi
|
||||||
|
|
||||||
|
| Metod | Putanja | Opis |
|
||||||
|
|-------|---------|------|
|
||||||
|
| GET | `/api/status` | Status uređaja i poslednji broj računa |
|
||||||
|
| GET | `/api/attention` | Aktivna upozorenja |
|
||||||
|
| POST | `/api/pin` | Verifikacija PIN-a (otključavanje BE) |
|
||||||
|
| GET | `/api/settings` | Podešavanja uređaja |
|
||||||
|
| POST | `/api/invoices` | Izdavanje fiskalnog računa |
|
||||||
|
| POST | `/api/invoices/final` | Finalizacija avansnog računa |
|
||||||
|
| GET | `/api/invoices/last` | Poslednji izdati račun |
|
||||||
|
| GET | `/api/invoices/:invoiceNumber` | Račun po broju |
|
||||||
|
| POST | `/api/invoices/search` | Pretraga računa |
|
||||||
|
|
||||||
|
Brojači, potpisane priznanice, QR kodovi i JSON podaci o računima čuvaju se u `Fisk/data/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Demo mod
|
### Demo mod
|
||||||
|
|
||||||
Demo mod pokreće potpuno funkcionalnu kopiju sa pre-kreiranim nalogom `Demo` / `Demo1234` (admin). Promena lozinke i 2FA su blokirani. Bekap je ograničen na 2 kopije.
|
Demo mod pokreće potpuno funkcionalnu kopiju sa pre-kreiranim nalogom `Demo` / `Demo1234` (admin). Promena lozinke i 2FA su blokirani. Bekap je ograničen na 2 kopije.
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
teron-mock:
|
||||||
|
image: ghcr.io/dalibor31/ntech-fisk:latest
|
||||||
|
container_name: teron_mock
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4566:4566"
|
||||||
|
volumes:
|
||||||
|
- teron-data:/app/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
teron-data:
|
||||||
Reference in New Issue
Block a user