feat: bump client-services (accumulated feature work + deploy fixes)

Snapshot of in-progress work across local_backend, manager_dashboard,
and waiter_pwa (pricing, chat, fiscal, prep zones, recovery codes, CRM,
inventory, permissions), plus the nginx/docker-compose deploy fixes for
the Unraid + NPM reverse-proxy setup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 10:00:14 +03:00
parent 02ec1aa28f
commit 34ae328b0d
182 changed files with 34874 additions and 3556 deletions

View File

@@ -0,0 +1,114 @@
"""
Greek code page probe — NETUM NT8330L (or any unknown printer)
Usage: python print_codepage_probe.py <IP> [PORT]
Example: python print_codepage_probe.py 192.168.1.50 9100
Prints one long receipt that tries every candidate (n, encoding) combination.
Circle the block where you can read "ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ" correctly.
That block tells you the codepage_n value to use in the printer profile.
"""
import sys
from escpos.printer import Network
IP = sys.argv[1] if len(sys.argv) > 1 else "192.168.1.50"
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9100
# (n_value, python_encoding, label)
# Each will be tested independently with a fresh ESC @ reset.
CANDIDATES = [
# Standard Epson table assignments for Greek
(14, "cp737", "n=14 CP737 (Epson standard slot)"),
(38, "cp737", "n=38 CP737 (alt slot / CP869 area)"),
(11, "cp737", "n=11 CP737 (CP851 slot)"),
(47, "cp737", "n=47 CP737 (CP1253 slot, cp737 bytes)"),
# Same slots but with cp869 encoding (different byte layout)
(14, "cp869", "n=14 CP869 (Greek DOS #2)"),
(38, "cp869", "n=38 CP869 (alt slot)"),
# Windows / ISO encodings
(47, "cp1253", "n=47 CP1253 (Windows Greek)"),
(15, "iso8859_7", "n=15 ISO-8859-7"),
(14, "iso8859_7", "n=14 ISO-8859-7"),
# The Jolimark value, for reference
(29, "cp737", "n=29 CP737 (Jolimark confirmed)"),
# A few more obscure slots some Chinese-made printers use
(16, "cp737", "n=16 CP737 (rare slot)"),
(18, "cp737", "n=18 CP737 (rare slot)"),
(21, "cp737", "n=21 CP737 (rare slot)"),
]
GREEK_SAMPLE = "ΚΑΛΗΜΕΡΑ ΕΛΛΑΔΑ"
GREEK_LOWER = "καλημέρα ελλάδα"
GREEK_DIGITS = "ΤΙΜΗ: 12.50 ευρώ"
def probe(n: int, encoding: str, label: str):
try:
p = Network(IP, PORT, timeout=8)
p._raw(b'\x1b\x40') # ESC @ full reset
p._raw(bytes([0x1b, 0x74, n])) # ESC t n — select code page
# Label in plain ASCII (always safe)
p._raw(b'\x1b\x21\x00') # normal size
p._raw(f"[{label}]\n".encode('ascii', errors='replace'))
# Greek sample in the candidate encoding
try:
greek_bytes = GREEK_SAMPLE.encode(encoding, errors='replace')
lower_bytes = GREEK_LOWER.encode(encoding, errors='replace')
digit_bytes = GREEK_DIGITS.encode(encoding, errors='replace')
except LookupError:
p._raw(b' (encoding not available)\n')
p._raw(b'\n')
p.close()
return
p._raw(b'\x1b\x21\x08') # bold
p._raw(greek_bytes + b'\n')
p._raw(b'\x1b\x21\x00') # normal
p._raw(lower_bytes + b'\n')
p._raw(digit_bytes + b'\n')
p._raw(b'\n') # spacer
p.close()
print(f" OK {label}")
except Exception as e:
print(f" ERR {label}: {e}")
def main():
print(f"Probing {IP}:{PORT}")
print(f"Testing {len(CANDIDATES)} combinations...\n")
# Print header block
try:
p = Network(IP, PORT, timeout=8)
p._raw(b'\x1b\x40')
p._raw(b'\x1b\x61\x01') # center
p._raw(b'\x1b\x21\x30') # double width+height
p._raw(b'GREEK PROBE\n')
p._raw(b'\x1b\x21\x00')
p._raw(b'\x1b\x61\x00') # left
p._raw(b'Circle the block with readable Greek.\n')
p._raw(b'Looking for: KALIMERA ELLADA\n')
p._raw(b'================================================\n')
p._raw(b'\n')
p.close()
except Exception as e:
print(f"Header failed: {e}")
return
for (n, enc, label) in CANDIDATES:
probe(n, enc, label)
# Footer + cut
try:
p = Network(IP, PORT, timeout=8)
p._raw(b'\x1b\x40')
p._raw(b'================================================\n')
p._raw(b'END OF PROBE\n')
p._raw(b'\n\n\n')
p.cut()
p.close()
print("\nDone. Read the printout and note which block shows readable Greek.")
except Exception as e:
print(f"Footer failed: {e}")
if __name__ == "__main__":
main()