Merge branch 'develop'

# Conflicts:
#	internal/handler/podesavanja.go
This commit is contained in:
2026-07-05 03:17:31 +02:00
7 changed files with 62 additions and 13 deletions
+1 -1
View File
@@ -392,7 +392,7 @@ def _build_invoice_response(req, request_id):
json.dumps(vl_payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
).decode("ascii")
scheme = "https" if VERIFY_HOST.startswith("https://") else "http"
host = VERIFY_HOST.removeprefix("https://").removeprefix("http://")
host = VERIFY_HOST.removeprefix("https://").removeprefix("http://").rstrip("/")
verification_url = f"{scheme}://{host}/v/?vl={urllib.parse.quote(vl, safe='')}"
else:
verification_url = f"https://sandbox.suf.purs.gov.rs/v/?vl={invoice_number}"
+13
View File
@@ -253,6 +253,13 @@ services:
image: ghcr.io/dalibor31/ntech-fisk:latest
container_name: teron_mock
restart: unless-stopped
environment:
- BE_HOST=ntech # NTech service name on the shared network — required so the
- BE_PORT=4567 # mock can read company data (name/PIB/address) from the card emulator
- VERIFY_HOST=https://ntech.your-domain.com # takes precedence over the "verify_host" setting
# in NTech's UI (the mock can't see ntech.db) —
# without it the QR links to sandbox.suf.purs.gov.rs
# and is sparse instead of encoding the full invoice
volumes:
- teron-data:/app/data
networks:
@@ -267,6 +274,8 @@ networks:
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.
`BE_HOST`/`BE_PORT` must point to the NTech container's card emulator (`internal/be`, TCP port 4567). Without them, `teron-mock` defaults to `127.0.0.1:4567`, which inside its own container never reaches NTech — the mock then silently falls back to placeholder company data ("Test Company DOO", TIN `RS000000000`) instead of your real business profile.
To run as a standalone Docker container:
```yaml
@@ -276,6 +285,10 @@ services:
image: ghcr.io/dalibor31/ntech-fisk:latest
container_name: teron_mock
restart: unless-stopped
environment:
- BE_HOST=ntech # adjust to the NTech container's name/hostname on this network
- BE_PORT=4567
- VERIFY_HOST=https://ntech.your-domain.com
ports:
- "4566:4566"
volumes:
+13
View File
@@ -253,6 +253,13 @@ services:
image: ghcr.io/dalibor31/ntech-fisk:latest
container_name: teron_mock
restart: unless-stopped
environment:
- BE_HOST=ntech # naziv NTech servisa na deljenoj mreži — neophodno da bi mock
- BE_PORT=4567 # mogao da pročita podatke firme (naziv/PIB/adresa) sa kartica emulatora
- VERIFY_HOST=https://ntech.tvoja-firma.rs # ima prednost nad podešavanjem "verify_host" u
# NTech UI-ju (mock ne vidi ntech.db) — bez ovoga
# QR vodi na sandbox.suf.purs.gov.rs i redak je
# umesto da enkoduje ceo račun
volumes:
- teron-data:/app/data
networks:
@@ -267,6 +274,8 @@ networks:
Servis `teron-mock` je dostupan iz `ntech` kontejnera na adresi `http://teron-mock:4566` preko interne Docker mreže — port nije izložen spolja.
`BE_HOST`/`BE_PORT` moraju pokazivati na kartica emulator NTech kontejnera (`internal/be`, TCP port 4567). Bez toga, `teron-mock` po defaultu koristi `127.0.0.1:4567`, što unutar sopstvenog kontejnera nikad ne stiže do NTech-a — mock onda tiho pada na test podatke firme ("Test Company DOO", PIB `RS000000000`) umesto tvog stvarnog profila firme.
Za pokretanje kao samostalni Docker kontejner:
```yaml
@@ -276,6 +285,10 @@ services:
image: ghcr.io/dalibor31/ntech-fisk:latest
container_name: teron_mock
restart: unless-stopped
environment:
- BE_HOST=ntech # prilagodi imenu/hostname-u NTech kontejnera na ovoj mreži
- BE_PORT=4567
- VERIFY_HOST=https://ntech.tvoja-firma.rs
ports:
- "4566:4566"
volumes:
+1 -1
View File
@@ -151,7 +151,7 @@ func main() {
h.Verzija = Verzija
h.JelDemo = os.Getenv("NTECH_ENV") == "demo"
if h.JelDemo {
h.Verzija = "DEMO verzija"
h.Verzija = "DEMO - " + h.Verzija
if err := postaviDemoKorisnika(context.Background(), h.KorisniciRepo); err != nil {
slog.Warn("demo: greška pri postavljanju demo korisnika", "error", err)
}
+6
View File
@@ -3,6 +3,12 @@ services:
image: ghcr.io/dalibor31/ntech-fisk:latest
container_name: teron_mock
restart: unless-stopped
environment:
- BE_HOST=ntech # naziv NTech servisa na ntech-net mreži — bez ovoga mock ne
- BE_PORT=4567 # može da pročita firmu sa kartica emulatora (pada na test podatke)
- VERIFY_HOST=https://ntech.tvoja-firma.rs # ima prednost nad "Podešavanja → Fiskalizacija"
# u NTech UI-ju (mock ne vidi ntech.db); bez ovoga
# QR vodi na sandbox.suf.purs.gov.rs i redak je
volumes:
- teron-data:/app/data
networks:
+16 -8
View File
@@ -1125,17 +1125,25 @@ func jePrivatnaAdresa(hostname string) bool {
if hostname == "localhost" {
return true
}
ip := net.ParseIP(hostname)
if ip == nil {
// Nije literalna IP adresa (npr. Docker Compose ime servisa poput
// "teron-mock") — razrešavamo je preko DNS-a pa proveravamo
// razrešenu adresu istim pravilima kao dole.
adrese, err := net.LookupIP(hostname)
if err != nil || len(adrese) == 0 {
if ip := net.ParseIP(hostname); ip != nil {
return jePrivatnaIP(ip)
}
// Hostname (npr. Docker Compose service name kao "teron-mock") — razreši
// preko DNS-a i dozvoli samo ako SVE dobijene adrese spadaju u privatne
// opsege (localhost/127/10/172.16-31/192.168).
ips, err := net.LookupIP(hostname)
if err != nil || len(ips) == 0 {
return false
}
for _, ip := range ips {
if !jePrivatnaIP(ip) {
return false
}
ip = adrese[0]
}
return true
}
func jePrivatnaIP(ip net.IP) bool {
ip4 := ip.To4()
if ip4 == nil {
return false
+12 -3
View File
@@ -228,6 +228,15 @@
}
var observer = new MutationObserver(function(){
observer.disconnect();
// fiskalizacija je best-effort — ako ESIR/PFR nije bio dostupan,
// .fiskalni-racun kartica se neće pojaviti (v. FiskalGreska upozorenje
// na stranici); tada ne navigiramo tab na nepostojeći račun (praznina/404),
// nego prazan tab zatvorimo.
var imaRacun = sadrzaj.querySelector('.fiskalni-racun');
if (!imaRacun) {
if (tab && !tab.closed) tab.close();
return;
}
// jedan prozor — server u istu stranicu ubacuje i povraćaj viška
// avansa (ako postoji), da brauzer ne blokira drugi popup
if (tab && !tab.closed) {
@@ -1015,7 +1024,7 @@
</div>
{{if .FiskalniRacun}}
<div class="kartica detalji-kartica animiraj">
<div class="kartica detalji-kartica animiraj fiskalni-racun">
<div style="margin-bottom:12px;padding-bottom:10px;border-bottom:0.5px solid var(--ivica);display:flex;justify-content:space-between;align-items:center;">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">
{{if eq .FiskalniRacun.TipRacuna "Advance"}}Avansni fiskalni račun{{else}}Fiskalni račun{{end}}
@@ -1046,7 +1055,7 @@
{{end}}
{{if .AvansRacun}}
<div class="kartica detalji-kartica animiraj">
<div class="kartica detalji-kartica animiraj fiskalni-racun">
<div style="margin-bottom:12px;padding-bottom:10px;border-bottom:0.5px solid var(--ivica);display:flex;justify-content:space-between;align-items:center;">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Avansni fiskalni račun</span>
<a href="/servis/{{.Nalog.ID}}/fiskalni-racun?tip=avans" target="_blank" class="btn-sekundarno" style="font-size:12px;padding:4px 12px;">Štampaj kopiju</a>
@@ -1068,7 +1077,7 @@
{{end}}
{{if .PovracajAvansa}}
<div class="kartica detalji-kartica animiraj">
<div class="kartica detalji-kartica animiraj fiskalni-racun">
<div style="margin-bottom:12px;padding-bottom:10px;border-bottom:0.5px solid var(--ivica);display:flex;justify-content:space-between;align-items:center;">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Povraćaj viška avansa</span>
<a href="/servis/{{.Nalog.ID}}/fiskalni-racun?tip=povracaj" target="_blank" class="btn-sekundarno" style="font-size:12px;padding:4px 12px;">Štampaj kopiju</a>