Stav 23.06.2026
This commit is contained in:
Generated
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (pokladna)" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PyPackaging">
|
||||||
|
<option name="earlyReleasesAsUpgrades" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/pokladna.iml" filepath="$PROJECT_DIR$/.idea/pokladna.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+12
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.10 (pokladna)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import tst_data
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
|
||||||
|
cenik=tst_data.create_tst_cenik("01")
|
||||||
|
|
||||||
|
for p in cenik.cenpol:
|
||||||
|
for pos in p.pos_pc:
|
||||||
|
print(p.d_name, pos.page, pos.line, pos.col)
|
||||||
|
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="01",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
ctx = get_ctx()
|
||||||
|
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
setup = api_call.load_setup_API(ctx)
|
||||||
|
api_call.debugrepl_cenik_API(ctx)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#replace ceniku na jeden request
|
||||||
|
import tst_data
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
|
||||||
|
# ---------- vytvoření testovacího ceníku ----------
|
||||||
|
cenik = tst_data.create_tst_cenik("01")
|
||||||
|
for p in cenik.cenpol:
|
||||||
|
for pos in p.pos_pc:
|
||||||
|
print(p.d_name, pos.page, pos.line, pos.col)
|
||||||
|
|
||||||
|
# ---------- API context ----------
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="01",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
ctx = get_ctx()
|
||||||
|
# ---------- login ----------
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
# ---------- načtení setup ----------
|
||||||
|
setup = api_call.load_setup_API(ctx)
|
||||||
|
# ---------- uložení CELÉHO ceníku ----------
|
||||||
|
api_call.debugrepl2_cenik_API(
|
||||||
|
ctx,
|
||||||
|
cenik.cenpol # ← list[CenPolCreate]
|
||||||
|
)
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#testovaci program pro nahrani mapy stolu
|
||||||
|
# replace mapa_stolu na jeden request
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
import data
|
||||||
|
|
||||||
|
# ---------- vytvoření testovací mapy ----------
|
||||||
|
def create_tst_mapa():
|
||||||
|
return data.MapaStolu(
|
||||||
|
pokladny=["01", "07"],
|
||||||
|
rooms=[
|
||||||
|
data.Room(
|
||||||
|
room_name="Hlavni",
|
||||||
|
stoly=[
|
||||||
|
data.Table(id="1", name="Stůl 1", pos_x=50, pos_y=50, width=100, height=100, radius=0),
|
||||||
|
data.Table(id="2", name="Stůl 2", pos_x=200, pos_y=50, width=100, height=100, radius=1),
|
||||||
|
data.Table(id="1", name="VIP", pos_x=150, pos_y=500, width=100, height=100, radius=1.0), # kulatý
|
||||||
|
data.Table(id="2", name="Bar", pos_x=380, pos_y=420, width=100, height=100, radius=0.0), # čtverec
|
||||||
|
data.Table(id="3", name="Rodina", pos_x= 20, pos_y=280, width=180, height=100, radius=0.2),# obdélník
|
||||||
|
data.Table(id="R4", name="Personal_dopo", pos_x=900, pos_y=520, width=120, height=120, radius=0.4),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
data.Room(
|
||||||
|
room_name="Salonek",
|
||||||
|
stoly=[
|
||||||
|
data.Table(id="10", name="S1", pos_x=50, pos_y=50, width=80, height=80, radius=0),
|
||||||
|
data.Table(id="R4", name="Personal_dopo", pos_x=900, pos_y=520, width=120, height=120, radius=0.4),
|
||||||
|
data.Table(id="12", name="Malý", pos_x=700, pos_y=220, width=90, height=90, radius=0.0),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------- API context ----------
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="01",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
ctx = get_ctx()
|
||||||
|
|
||||||
|
# ---------- login ----------
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
|
||||||
|
# ---------- vytvoření mapy ----------
|
||||||
|
mapa = create_tst_mapa()
|
||||||
|
|
||||||
|
print("\n--- TEST MAPA (CREATE) ---")
|
||||||
|
for room in mapa.rooms:
|
||||||
|
print("Room:", room.room_name)
|
||||||
|
for t in room.stoly:
|
||||||
|
print(" ", t.id, t.name, t.pos_x, t.pos_y)
|
||||||
|
|
||||||
|
# ---------- uložení mapy ----------
|
||||||
|
api_call.save_mapa_stolu_API(ctx, mapa)
|
||||||
|
|
||||||
|
print("\nMapa uložena\n")
|
||||||
|
|
||||||
|
# ---------- načtení mapy ----------
|
||||||
|
mapa_loaded = api_call.load_mapa_stolu_API(ctx)
|
||||||
|
api_call.logout_API(ctx)
|
||||||
|
print("\n--- TEST MAPA (LOADED) ---")
|
||||||
|
for room in mapa_loaded.rooms:
|
||||||
|
print("Room:", room.room_name)
|
||||||
|
for t in room.stoly:
|
||||||
|
print(" ", t.id, t.name, t.pos_x, t.pos_y)
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# testovací program pro reset users
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
import data
|
||||||
|
# ---------- vytvoření test users ----------
|
||||||
|
def create_tst_users():
|
||||||
|
return [
|
||||||
|
data.UserIn(
|
||||||
|
name="admin",
|
||||||
|
heslo="1234",
|
||||||
|
permits=[
|
||||||
|
"SPLIT",
|
||||||
|
"PLATBA",
|
||||||
|
"PL_HOTOVE",
|
||||||
|
"CLOSE",
|
||||||
|
"STORNO_PL",
|
||||||
|
"PL_SELECT",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
data.UserIn(
|
||||||
|
name="obsluha",
|
||||||
|
heslo="1111",
|
||||||
|
permits=[
|
||||||
|
"PLATBA",
|
||||||
|
"PL_HOTOVE",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
data.UserIn(
|
||||||
|
name="Petr",
|
||||||
|
heslo="123",
|
||||||
|
permits=[
|
||||||
|
"PL_HOTOVE",
|
||||||
|
"SPLIT",
|
||||||
|
"PLATBA",
|
||||||
|
"CLOSE",
|
||||||
|
"STORNO_PL",
|
||||||
|
"PL_SELECT",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ---------- API context ----------
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="01",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
ctx = get_ctx()
|
||||||
|
# ---------- login ----------
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
# ---------- vytvoření users ----------
|
||||||
|
users = create_tst_users()
|
||||||
|
print("\n--- TEST USERS (CREATE) ---")
|
||||||
|
for u in users:
|
||||||
|
print("User:", u.name, u.permits)
|
||||||
|
# ---------- reset users ----------
|
||||||
|
api_call.reset_users_API(ctx, users)
|
||||||
|
print("\nUsers resetnuty\n")
|
||||||
|
# ---------- (volitelně) načtení ----------
|
||||||
|
users_loaded = api_call.load_users_API(ctx)
|
||||||
|
print("\n--- TEST USERS (LOADED) ---")
|
||||||
|
for u in users_loaded:
|
||||||
|
print("User:", u.name, u.permits)
|
||||||
|
# ---------- logout ----------
|
||||||
|
api_call.logout_API(ctx)
|
||||||
@@ -0,0 +1,655 @@
|
|||||||
|
{% if printer %}
|
||||||
|
{{ printer.reset }}
|
||||||
|
{% if hlavicka.uz_cislo is defined %}
|
||||||
|
{{ hlavicka.titulka }} {{ hlavicka.uz_cislo }}
|
||||||
|
{% else %}
|
||||||
|
{{ hlavicka.titulka }} {{ hlavicka.c_uzaverka }}
|
||||||
|
{% endif %}
|
||||||
|
{{ hlavicka.uzaverka }}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.id_zkratka is defined %}
|
||||||
|
{{ hlavicka.id_zkratka}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h1 is defined %}
|
||||||
|
{{ hlavicka.h1}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h2 is defined %}
|
||||||
|
{{ hlavicka.h2}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h3 is defined %}
|
||||||
|
{{ hlavicka.h3}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h4 is defined %}
|
||||||
|
{{ hlavicka.h4}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h5 is defined %}
|
||||||
|
{{ hlavicka.h5}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h6 is defined %}
|
||||||
|
{{ hlavicka.h6}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h7 is defined %}
|
||||||
|
{{ hlavicka.h7}}
|
||||||
|
{% endif %}
|
||||||
|
{% if hlavicka.h8 is defined %}
|
||||||
|
{{ hlavicka.h8}}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
Od: {{ hlavicka.od }}
|
||||||
|
Do: {{ hlavicka.do }}
|
||||||
|
{% for section in sekcie %}
|
||||||
|
{{ "\n" }}{{ sekcie[section]['meno'] }}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ '\r' }}
|
||||||
|
{% if sekcie[section]['meno'] == "Zoznam uzávierok" %}
|
||||||
|
{{ "\n" }}Kasa Uzávierka
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['id_zkratka']|truncate(22, True, '') }} {{ sekcie[section]['data'][data]['uzaverka']}}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po cenových hladinách" %}
|
||||||
|
{% set prachy, prachy_puv = [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
Cenova hladina {{ sekcie[section]['data'][data]['cen_hlad'] }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy_puv'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy_puv']) }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if prachy_puv.append(prachy_puv.pop() + sekcie[section]['data'][data]['prachy_puv']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy_puv[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy_puv[0]) }}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po druhoch platby" %}
|
||||||
|
{% set cena_pl, cena_pl_puv, tip = [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave TIP
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% set row = sekcie[section]['data'][data] %}
|
||||||
|
{% set pred = row.get('cena_pl_puv', row['cena_pl']) %}
|
||||||
|
{% set popis = row['druh_pl'] if row['popis'] is none else row['popis'] %}
|
||||||
|
{{ popis|truncate(12, True, '') }} {{ '%8.2f'|format(pred) }}{{ '%8.2f'|format(row['cena_pl']) }}{{ '%8.2f'|format(row['tip']) }}
|
||||||
|
{% if cena_pl_puv.append(cena_pl_puv.pop() + pred) %}{% endif %}
|
||||||
|
{% if cena_pl.append(cena_pl.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% if tip.append(tip.pop() + sekcie[section]['data'][data]['tip']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {{ '%8.2f'|format(cena_pl_puv[0]) }}{{ '%8.2f'|format(cena_pl[0]) }}{{ '%8.2f'|format(tip[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po menách" %}
|
||||||
|
{% set cena_pl = [0.0] %}
|
||||||
|
{{ "\n" }}Mena Tržba v EUR Tržba{{ "\n" }}{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['mena']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['cena_pl'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['cena_pl']) }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['cena_mena'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['cena_mena']) }}
|
||||||
|
{% if cena_pl.append(cena_pl.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}
|
||||||
|
{{ "\n" }}C E L K O M {% for i in range(1, 11-('%0.2f'|format(cena_pl[0])|length)) %} {% endfor %}{{ '%0.2f'|format(cena_pl[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby za fiškálne platby" %}
|
||||||
|
{% set cena_pl, cena_pl_puv, tip = [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave TIP
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% set row = sekcie[section]['data'][data] %}
|
||||||
|
{% set pred = row.get('cena_pl_puv', row['cena_pl']) %}
|
||||||
|
{{ row['popis']|truncate(12, True, '') }} {{ '%8.2f'|format(pred) }}{{ '%8.2f'|format(row['cena_pl']) }}{{ '%8.2f'|format(row['tip']) }}
|
||||||
|
{% if cena_pl_puv.append(cena_pl_puv.pop() + pred) %}{% endif %}
|
||||||
|
{% if cena_pl.append(cena_pl.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% if tip.append(tip.pop() + sekcie[section]['data'][data]['tip']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {{ '%8.2f'|format(cena_pl_puv[0]) }}{{ '%8.2f'|format(cena_pl[0]) }}{{ '%8.2f'|format(tip[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Úhrady pohľadávok" %}
|
||||||
|
{% set cena_pl = [0.0] %}
|
||||||
|
{{ "\n" }} Tržba
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['druh_pl'] }} {{ sekcie[section]['data'][data]['username']|truncate(15, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['cena_pl'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['cena_pl']) }}
|
||||||
|
{% if cena_pl.append(cena_pl.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(cena_pl[0])|length)) %} {% endfor %}{{ '%0.2f'|format(cena_pl[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po manageroch" %}
|
||||||
|
{% set prachy, prachy_puv = [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['id_zkratka']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy_puv'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy_puv']) }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if prachy_puv.append(prachy_puv.pop() + sekcie[section]['data'][data]['prachy_puv']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy_puv[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy_puv[0]) }}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po manageroch a daniach" %}
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{{ "\n" }} Základ Daň Celkom
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['id_zkratka']|truncate(24, True, '') }} {{ '%0.0f'|format(sekcie[section]['data'][data]['dan_sazba']) }}%
|
||||||
|
{% if sekcie[section]['data'][data]['dan'] is defined %}
|
||||||
|
{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% else %}
|
||||||
|
{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Na odovzdanie" %}
|
||||||
|
{% set suma, celkom, memodovzdat, memdruh_pl, memtxt, mempocet = [0.0], [0.0], ['?'],['?'],['?'],[0] %}
|
||||||
|
{{ "\n" }}
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if memodovzdat[0]=='?' or memodovzdat[0]==sekcie[section]['data'][data]['odovzdat'] %}
|
||||||
|
{% if memdruh_pl[0]=='?' or memdruh_pl[0]|trim()==sekcie[section]['data'][data]['druh_pl']|trim() %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] != 3 %}
|
||||||
|
{% if suma.append(suma.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% if celkom.append(celkom.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['j0']|truncate(21, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(18, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Zo včera+ {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Zo včera+ {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(14, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 3 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(14, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 4 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Prenos- {{ sekcie[section]['data'][data]['j0']|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Prenos- {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(16, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if memdruh_pl|length > 0 %}{{ memdruh_pl.remove(memdruh_pl[0]) or ""}}{% endif %}
|
||||||
|
{% if memdruh_pl.append(sekcie[section]['data'][data]['druh_pl']) %}{% endif %}
|
||||||
|
{% if memtxt|length > 0 %}{{ memtxt.remove(memtxt[0]) or ""}}{% endif %}
|
||||||
|
{% if memtxt.append(sekcie[section]['data'][data]['j0']) %}{% endif %}
|
||||||
|
{% if memodovzdat|length > 0 %}{{ memodovzdat.remove(memodovzdat[0]) or "" }}{% endif %}
|
||||||
|
{% if memodovzdat.append(sekcie[section]['data'][data]['odovzdat']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
Odovzdať {{ memodovzdat[0]|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(suma[0])|length)) %} {% endfor %}{{ '%0.2f'|format(suma[0]) }}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
{% if mempocet.append(mempocet.pop()+1) %}{% endif %}
|
||||||
|
{% if suma|length > 0 %}{{ suma.remove(suma[0]) or ""}}{% endif %}
|
||||||
|
{% if suma.append(0.0) %}{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] != 3 %}
|
||||||
|
{% if suma.append(suma.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% if celkom.append(celkom.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['j0']|truncate(21, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(18, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Zo včera+ {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Zo včera+ {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(14, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 3 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(14, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 4 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Prenos- {{ sekcie[section]['data'][data]['j0']|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Prenos- {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(16, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if memdruh_pl|length > 0 %}{{ memdruh_pl.remove(memdruh_pl[0]) or ""}}{% endif %}
|
||||||
|
{% if memdruh_pl.append(sekcie[section]['data'][data]['druh_pl']) %}{% endif %}
|
||||||
|
{% if memtxt|length > 0 %}{{ memtxt.remove(memtxt[0]) or ""}}{% endif %}
|
||||||
|
{% if memtxt.append(sekcie[section]['data'][data]['j0']) %}{% endif %}
|
||||||
|
{% if memodovzdat|length > 0 %}{{ memodovzdat.remove(memodovzdat[0]) or "" }}{% endif %}
|
||||||
|
{% if memodovzdat.append(sekcie[section]['data'][data]['odovzdat']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
Odovzdať {{ memodovzdat[0]|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(suma[0])|length)) %} {% endfor %}{{ '%0.2f'|format(suma[0]) }}
|
||||||
|
{% if mempocet.append(mempocet.pop()+1) %}{% endif %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
{% if mempocet[0] > 1 %}
|
||||||
|
ODOVZDAŤ {{ memodovzdat[0] }} {% for i in range(1, 11-('%0.2f'|format(celkom[0])|length)) %} {% endfor %}{{ '%0.2f'|format(celkom[0]) }}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
{% endif %}
|
||||||
|
{% if mempocet|length > 0 %}{{ mempocet.remove(mempocet[0]) or ""}}{% endif %}
|
||||||
|
{% if mempocet.append(0) %}{% endif %}
|
||||||
|
{% if suma|length > 0 %}{{ suma.remove(suma[0]) or ""}}{% endif %}
|
||||||
|
{% if suma.append(0.0) %}{% endif %}
|
||||||
|
{% if celkom|length > 0 %}{{ celkom.remove(celkom[0]) or ""}}{% endif %}
|
||||||
|
{% if celkom.append(0.0) %}{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] < 3 %}
|
||||||
|
{% if suma.append(suma.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% if celkom.append(celkom.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['j0']|truncate(21, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Tržba {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(18, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Úhrada {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['typ'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 0 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Vklady {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 1 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['j0']|truncate(20, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Výbery {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 2 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Prevod+{{ sekcie[section]['data'][data]['j0']|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Prevod+{{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(16, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 3 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['j0']|truncate(17, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Uzávierka {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(14, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['operacia'] == 4 %}
|
||||||
|
{% if sekcie[section]['data'][data]['prn_no'] is none %}
|
||||||
|
Prevod- {{ sekcie[section]['data'][data]['j0']|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% else %}
|
||||||
|
Prevod- {{ sekcie[section]['data'][data]['prn_no']|truncate(2, True, '') }} {{ sekcie[section]['data'][data]['j0']|truncate(16, True, '') }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if memdruh_pl|length > 0 %}{{ memdruh_pl.remove(memdruh_pl[0]) or ""}}{% endif %}
|
||||||
|
{% if memdruh_pl.append(sekcie[section]['data'][data]['druh_pl']) %}{% endif %}
|
||||||
|
{% if memtxt|length > 0 %}{{ memtxt.remove(memtxt[0]) or ""}}{% endif %}
|
||||||
|
{% if memtxt.append(sekcie[section]['data'][data]['j0']) %}{% endif %}
|
||||||
|
{% if memodovzdat|length > 0 %}{{ memodovzdat.remove(memodovzdat[0]) or "" }}{% endif %}
|
||||||
|
{% if memodovzdat.append(sekcie[section]['data'][data]['odovzdat']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
Odovzdať {{ memodovzdat[0]|truncate(19, True, '') }} {% for i in range(1, 11-('%0.2f'|format(suma[0])|length)) %} {% endfor %}{{ '%0.2f'|format(suma[0]) }}
|
||||||
|
{% if mempocet.append(mempocet.pop()+1) %}{% endif %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
{% if mempocet[0] > 1 %}
|
||||||
|
ODOVZDAŤ {{ memodovzdat[0] }} {% for i in range(1, 11-('%0.2f'|format(celkom[0])|length)) %} {% endfor %}{{ '%0.2f'|format(celkom[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if mempocet|length > 0 %}{{ mempocet.remove(mempocet[0]) or ""}}{% endif %}
|
||||||
|
{% if mempocet.append(0) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po DPH - fiškálne platby" %}
|
||||||
|
{% set prachy, dan, zaklad, round50 = [0.0], [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Daň Základ
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['round50'] is defined and sekcie[section]['data'][data]['round50'] != None %}
|
||||||
|
{% if round50.append(round50.pop() + sekcie[section]['data'][data]['round50']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['dan'] is defined %}
|
||||||
|
DPH {{ sekcie[section]['data'][data]['dan_sazba'] }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if dan.append(dan.pop() + sekcie[section]['data'][data]['dan']) %}{% endif %}
|
||||||
|
{% if zaklad.append(zaklad.pop() + sekcie[section]['data'][data]['zaklad']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['dan_sazba'] is defined %}
|
||||||
|
DPH {{ sekcie[section]['data'][data]['dan_sazba'] }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}{% for i in range(1, 10-('%0.2f'|format(dan[0])|length)) %} {% endfor %}{{ '%0.2f'|format(dan[0]) }}{% for i in range(1, 10-('%0.2f'|format(zaklad[0])|length)) %} {% endfor %}{{ '%0.2f'|format(zaklad[0]) }}
|
||||||
|
{% if round50[0]!=0 %}
|
||||||
|
ZAOKRÚHLENIE {% for i in range(1, 10-('%0.2f'|format(round50[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]) }}
|
||||||
|
Po ZAOKR. {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]+prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po DPH" %}
|
||||||
|
{% set prachy, dan, zaklad, round50 = [0.0], [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Daň Základ
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['round50'] is defined and sekcie[section]['data'][data]['round50'] != None %}
|
||||||
|
{% if round50.append(round50.pop() + sekcie[section]['data'][data]['round50']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['dan'] is defined %}
|
||||||
|
DPH {% for i in range(1, 5-('%0.1f'|format(sekcie[section]['data'][data]['dan_sazba'])|length)) %} {% endfor %}{{ '%0.1f'|format(sekcie[section]['data'][data]['dan_sazba']) }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if dan.append(dan.pop() + sekcie[section]['data'][data]['dan']) %}{% endif %}
|
||||||
|
{% if zaklad.append(zaklad.pop() + sekcie[section]['data'][data]['zaklad']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['dan_sazba'] is defined %}
|
||||||
|
DPH {% for i in range(1, 5-('%0.1f'|format(sekcie[section]['data'][data]['dan_sazba'])|length)) %} {% endfor %}{{ '%0.1f'|format(sekcie[section]['data'][data]['dan_sazba']) }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}{% for i in range(1, 10-('%0.2f'|format(dan[0])|length)) %} {% endfor %}{{ '%0.2f'|format(dan[0]) }}{% for i in range(1, 10-('%0.2f'|format(zaklad[0])|length)) %} {% endfor %}{{ '%0.2f'|format(zaklad[0]) }}
|
||||||
|
{% if round50[0]!=0 %}
|
||||||
|
ZAOKRÚHLENIE {% for i in range(1, 10-('%0.2f'|format(round50[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]) }}
|
||||||
|
Po ZAOKR. {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]+prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Žurnál storien" %}
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{% set prachy, celkom, memmeno, memoperacia, oldmeno = [0.0], [0.0],['?'],['?'],['?'] %}
|
||||||
|
{{ "\n" }}
|
||||||
|
Účet Platba Suma Pôv.účet
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if oldmeno|length > 0 %}{{ oldmeno.remove(oldmeno[0]) or ""}}{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['username'] is none %}
|
||||||
|
{% if oldmeno.append(sekcie[section]['data'][data]['autor']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if oldmeno.append(sekcie[section]['data'][data]['username']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if ((memmeno[0]=='?' or memmeno[0]==oldmeno[0]) and (memoperacia[0]=='?' or memoperacia[0]==sekcie[section]['data'][data]['text_sleva']|truncate(1,True,'') )) %}
|
||||||
|
{{'%5i'|format(sekcie[section]['data'][data]['ucet'])}} {% if sekcie[section]['data'][data]['j0'] is none %}{{sekcie[section]['data'][data]['druh_pl']|truncate(18, True, '')}}{% else %}{{sekcie[section]['data'][data]['j0']|truncate(18, True, '')}}{% endif %} {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['cena_pl'])|length)) %} {% endfor %}{{'%0.2f'|format(sekcie[section]['data'][data]['cena_pl']) }} {{sekcie[section]['data'][data]['text_sleva']| replace("@","")| replace("^","") }}
|
||||||
|
{% if celkom.append(celkom.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% if memmeno|length > 0 %}{{ memmeno.remove(memmeno[0]) or ""}}{% endif %}
|
||||||
|
{% if memmeno.append(oldmeno[0]) %}{% endif %}
|
||||||
|
{% if memoperacia|length > 0 %}{{ memoperacia.remove(memoperacia[0]) or "" }}{% endif %}
|
||||||
|
{% if memoperacia.append(sekcie[section]['data'][data]['text_sleva']|truncate(1,True,'')) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if memoperacia|length > 0 %}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
{% if memoperacia[0]=='@' %}Storno {% else %}Zmena platby {% endif %}{{memmeno[0]|trim()}}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
{% endif %}
|
||||||
|
{% if prachy|length > 0 %}{{ prachy.remove(prachy[0]) or ""}}{% endif %}
|
||||||
|
{% if prachy.append(0.0) %}{% endif %}
|
||||||
|
{{'%5i'|format(sekcie[section]['data'][data]['ucet'])}} {% if sekcie[section]['data'][data]['j0'] is none %}{{sekcie[section]['data'][data]['druh_pl']|truncate(18, True, '')}}{% else %}{{sekcie[section]['data'][data]['j0']|truncate(18, True, '')}}{% endif %} {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['cena_pl'])|length)) %} {% endfor %}{{'%0.2f'|format(sekcie[section]['data'][data]['cena_pl']) }} {{sekcie[section]['data'][data]['text_sleva']| replace("@","")| replace("^","") }}
|
||||||
|
{% if memmeno|length > 0 %}{{ memmeno.remove(memmeno[0]) or ""}}{% endif %}
|
||||||
|
{% if memmeno.append(oldmeno[0]) %}{% endif %}
|
||||||
|
{% if memoperacia|length > 0 %}{{ memoperacia.remove(memoperacia[0]) or "" }}{% endif %}
|
||||||
|
{% if memoperacia.append(sekcie[section]['data'][data]['text_sleva']|truncate(1,True,'')) %}{% endif %}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% if celkom.append(celkom.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if memoperacia|length > 0 %}
|
||||||
|
{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
{% if memoperacia[0]=='@' %}Storno {% else %}Zmena platby {% endif %}{{memmeno[0]|trim()}}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 10-('%0.2f'|format(celkom[0])|length)) %} {% endfor %}{{ '%0.2f'|format(celkom[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Počet účtov čašníka" %}
|
||||||
|
{{ "\n" }}Meno Kto Poč.Druh pl. Čiastka
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ (sekcie[section]['data'][data]['username']|truncate(13, True, '')) .ljust(13) }} {{ sekcie[section]['data'][data]['autor'] .ljust(3) }} {{ ('%0.0f'|format(sekcie[section]['data'][data]['pocet'])) .rjust(3) }} {{ (sekcie[section]['data'][data]['druh_pl']|truncate(10, True, '')) .ljust(10) }} {{ ('%0.2f'|format(sekcie[section]['data'][data]['suma'])) .rjust(6) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 21-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if sekcie[section]['meno'] == "Platby terminálom" %}
|
||||||
|
{{ "\n" }}Terminál Suma
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['prn_name'] }} {% for i in range(1, 18-('%0.2f'|format(sekcie[section]['data'][data]['suma'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['suma']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 21-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po platbách a daniach" %}
|
||||||
|
{% set prachy, dan, zaklad, round50 = [0.0], [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }}Sadzba Tržba Daň Základ
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if data != None %}
|
||||||
|
{% if sekcie[section]['data'][data]['round50'] is defined and sekcie[section]['data'][data]['round50'] != None %}
|
||||||
|
{% if round50.append(round50.pop() + sekcie[section]['data'][data]['round50']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['j0'] != None and sekcie[section]['data'][data]['dan_sazba'] is defined and sekcie[section]['data'][data]['dan_sazba'] != None %}
|
||||||
|
{{ sekcie[section]['data'][data]['j0']|truncate(40, True, '') }}
|
||||||
|
{{ sekcie[section]['data'][data]['dan_sazba'] }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if dan.append(dan.pop() + sekcie[section]['data'][data]['dan']) %}{% endif %}
|
||||||
|
{% if zaklad.append(zaklad.pop() + sekcie[section]['data'][data]['zaklad']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}{% for i in range(1, 10-('%0.2f'|format(dan[0])|length)) %} {% endfor %}{{ '%0.2f'|format(dan[0]) }}{% for i in range(1, 10-('%0.2f'|format(zaklad[0])|length)) %} {% endfor %}{{ '%0.2f'|format(zaklad[0]) }}
|
||||||
|
{% if round50[0]!=0 %}
|
||||||
|
ZAOKRÚHLENIE {% for i in range(1, 10-('%0.2f'|format(round50[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]) }}
|
||||||
|
Po ZAOKR. {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]+prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po fiškálnych platbách a daniach" %}
|
||||||
|
{% set prachy, dan, zaklad, round50 = [0.0], [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }}Sadzba Tržba Daň Základ
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if data != None %}
|
||||||
|
{% if sekcie[section]['data'][data]['round50'] is defined and sekcie[section]['data'][data]['round50'] != None %}
|
||||||
|
{% if round50.append(round50.pop() + sekcie[section]['data'][data]['round50']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if sekcie[section]['data'][data]['j0'] != None and sekcie[section]['data'][data]['dan_sazba'] is defined and sekcie[section]['data'][data]['dan_sazba'] != None %}
|
||||||
|
{{ sekcie[section]['data'][data]['j0']|truncate(40, True, '') }}
|
||||||
|
{{ sekcie[section]['data'][data]['dan_sazba'] }}% {% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if dan.append(dan.pop() + sekcie[section]['data'][data]['dan']) %}{% endif %}
|
||||||
|
{% if zaklad.append(zaklad.pop() + sekcie[section]['data'][data]['zaklad']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}{% for i in range(1, 10-('%0.2f'|format(dan[0])|length)) %} {% endfor %}{{ '%0.2f'|format(dan[0]) }}{% for i in range(1, 10-('%0.2f'|format(zaklad[0])|length)) %} {% endfor %}{{ '%0.2f'|format(zaklad[0]) }}
|
||||||
|
{% if round50[0]!=0 %}
|
||||||
|
ZAOKRÚHLENIE {% for i in range(1, 10-('%0.2f'|format(round50[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]) }}
|
||||||
|
Po ZAOKR. {% for i in range(1, 10-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(round50[0]+prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po druhoch" %}
|
||||||
|
{% set prachy, prachy_puv, mnozstvi = [0.0], [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave Počet
|
||||||
|
{% for data in sekcie[section]['data'] %}{% if sekcie[section]['data'][data]['mnozstvi'] is defined %}
|
||||||
|
{{ sekcie[section]['data'][data]['druh']|truncate(10, True, '') }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy_puv'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy_puv']) }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['mnozstvi'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['mnozstvi']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if prachy_puv.append(prachy_puv.pop() + sekcie[section]['data'][data]['prachy_puv']) %}{% endif %}
|
||||||
|
{% if mnozstvi.append(mnozstvi.pop() + sekcie[section]['data'][data]['mnozstvi']) %}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{{ sekcie[section]['data'][data]['druh'] }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy_puv'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy_puv']) }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if prachy_puv.append(prachy_puv.pop() + sekcie[section]['data'][data]['prachy_puv']) %}{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
CELKOM {% for i in range(1, 11-('%0.2f'|format(prachy_puv[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy_puv[0]) }}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}{% for i in range(1, 10-('%0.2f'|format(mnozstvi[0])|length)) %} {% endfor %}{{ '%0.2f'|format(mnozstvi[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Spotreba" %}
|
||||||
|
{% set ciastka = [0.0] %}
|
||||||
|
{% set last_category, last_section = ["s"], ["s"] %}
|
||||||
|
Počet Cena Hladina Čiastka DPH
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if last_section[0] != sekcie[section]['data'][data]['id_zkratka'] %}
|
||||||
|
{% if last_section.pop() %}{% endif %}
|
||||||
|
{{ sekcie[section]['data'][data]['id_zkratka'] }}
|
||||||
|
{% if last_section.append(sekcie[section]['data'][data]['id_zkratka']) %}{% endif %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
{% endif %}
|
||||||
|
{% if last_category[0] != sekcie[section]['data'][data]['druh'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['druh'] }}
|
||||||
|
{% if last_category.pop() %}{% endif %}
|
||||||
|
{% if last_category.append(sekcie[section]['data'][data]['druh']) %}{% endif %}{% for i in range(1, 40) %}-{% endfor %}{{ "\n" }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['data'][data]['jc'] is defined %}
|
||||||
|
{{ sekcie[section]['data'][data]['nazev'] }}
|
||||||
|
{% for i in range(1, 4-('%d'|format(sekcie[section]['data'][data]['mnozstvi']))|length) %} {% endfor %}{{ sekcie[section]['data'][data]['mnozstvi'] }}x {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['jc'])|length)) %} {% endfor %} {{ '%0.2f'|format(sekcie[section]['data'][data]['jc']) }} {{ sekcie[section]['data'][data]['cen_hlad'] }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['ciastka'])|length)) %} {% endfor %} {{ '%0.2f'|format(sekcie[section]['data'][data]['ciastka']) }} {{ sekcie[section]['data'][data]['dph'] }}%
|
||||||
|
{% else %}
|
||||||
|
{{ sekcie[section]['data'][data]['nazev'] }}
|
||||||
|
{% for i in range(1, 4-('%d'|format(sekcie[section]['data'][data]['mnozstvi']))|length) %} {% endfor %}{{ sekcie[section]['data'][data]['mnozstvi'] }}x {{ sekcie[section]['data'][data]['cen_hlad'] }} {{ sekcie[section]['data'][data]['spart'] }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['ciastka'])|length)) %} {% endfor %} {{ '%0.2f'|format(sekcie[section]['data'][data]['ciastka']) }} {{ sekcie[section]['data'][data]['dph'] }}%
|
||||||
|
{% endif %}
|
||||||
|
{% if ciastka.append(ciastka.pop() + sekcie[section]['data'][data]['ciastka']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(ciastka[0])|length)) %} {% endfor %}{{ '%0.2f'|format(ciastka[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po čašníkoch" %}
|
||||||
|
{% set prachy, prachy_puv = [0.0], [0.0] %}
|
||||||
|
{{ "\n" }} Tržba Po zľave
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['username'] != None %}{{ (sekcie[section]['data'][data]['username']+" ")|truncate(17, True, '') }}{% else %} {% endif %} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy_puv'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy_puv']) }}{% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% if prachy_puv.append(prachy_puv.pop() + sekcie[section]['data'][data]['prachy_puv']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy_puv[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy_puv[0]) }}{% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% if prachy_puv[0] != prachy[0] %}
|
||||||
|
Z Ľ A V A {% for i in range(1, 11-('%0.2f'|format(prachy_puv[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy_puv[0]-prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po čašníkoch a druhoch platieb" %}
|
||||||
|
{% set cena_pl = [0.0] %}
|
||||||
|
{{ "\n" }}Meno Autor Čiastka Druh
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['username'] != None %}{{ (sekcie[section]['data'][data]['username']+" ")|truncate(17, True, '') }}{% else %} {% endif %}{{ sekcie[section]['data'][data]['autor'] }} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['cena_pl'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['cena_pl']) }} {{ sekcie[section]['data'][data]['druh_pl']|truncate(6, True, '', 0) }}
|
||||||
|
{% if cena_pl.append(cena_pl.pop() + sekcie[section]['data'][data]['cena_pl']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(cena_pl[0])|length)) %} {% endfor %}{{ '%0.2f'|format(cena_pl[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po čašníkoch v hotovosti" %}
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{{ "\n" }} Po zľave
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['username'] != None %}{{ (sekcie[section]['data'][data]['username']+" ")|truncate(17, True, '') }}{% else %} {% endif %} {% for i in range(1, 11-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Tržby po platbách, manageroch a daniach" %}
|
||||||
|
{% set prachy = [0.0] %}
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['id_zkratka']|truncate(24, True, '') }} {{ sekcie[section]['data'][data]['druh_pl'] }} {{ '%0.0f'|format(sekcie[section]['data'][data]['dan_sazba']) }}%
|
||||||
|
{% if sekcie[section]['data'][data]['dan'] is defined %}
|
||||||
|
{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['zaklad'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['zaklad']) }}{% for i in range(1, 10-('%0.2f'|format(sekcie[section]['data'][data]['dan'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['dan']) }}{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% else %}
|
||||||
|
{% for i in range(1, 15-('%0.2f'|format(sekcie[section]['data'][data]['prachy'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['prachy']) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if prachy.append(prachy.pop() + sekcie[section]['data'][data]['prachy']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(prachy[0])|length)) %} {% endfor %}{{ '%0.2f'|format(prachy[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Sumár vkladov a výberov" %}
|
||||||
|
{% set ciastka = [0.0] %}
|
||||||
|
{{ "\n" }}
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{% if sekcie[section]['data'][data]['username'] != None %}{{ (sekcie[section]['data'][data]['username']+" ")|truncate(20, True, '') }}{% else %} {% endif %}{{ sekcie[section]['data'][data]['datum'] }}
|
||||||
|
{{ (sekcie[section]['data'][data]['popis'])|truncate(27, True, '') }} {% for i in range(1, 12-('%0.2f'|format(sekcie[section]['data'][data]['ciastka'])|length)) %} {% endfor %}{{ '%0.2f'|format(sekcie[section]['data'][data]['ciastka']) }}
|
||||||
|
{% if ciastka.append(ciastka.pop() + sekcie[section]['data'][data]['ciastka']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.2f'|format(ciastka[0])|length)) %} {% endfor %}{{ '%0.2f'|format(ciastka[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Predaj alkoholu" %}
|
||||||
|
{% set pocet = [0.0] %}
|
||||||
|
{{ "\n" }}Ean Názov Počet
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ sekcie[section]['data'][data]['ean']|truncate(13, True, '') }} {% if sekcie[section]['data'][data]['nazev'] %}{{ (sekcie[section]['data'][data]['nazev']+" ")|truncate(19, True, '') }}{% else %} {% endif %}{% for i in range(1, 7-('%0.0f'|format(sekcie[section]['data'][data]['pocet'])|length)) %} {% endfor %}{{ sekcie[section]['data'][data]['pocet'] }}
|
||||||
|
{% if pocet.append(pocet.pop() + sekcie[section]['data'][data]['pocet']) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
C E L K O M {% for i in range(1, 11-('%0.0f'|format(pocet[0])|length)) %} {% endfor %}{{ '%0.0f'|format(pocet[0]) }}
|
||||||
|
{% endif %}
|
||||||
|
{% if sekcie[section]['meno'] == "Otvorené stoly" %}
|
||||||
|
{{ "\n" }}Stôl Suma
|
||||||
|
{% for data in sekcie[section]['data'] %}
|
||||||
|
{{ "%-27s%12s" % ( ((sekcie[section]['data'][data]['stol']|trim) ~ '/' ~ (sekcie[section]['data'][data]['miestnost']|trim))[:27], "%0.2f" % sekcie[section]['data'][data]['suma']) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% for i in range(1, 40) %}={% endfor %}{{ "\n" }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if printer %}
|
||||||
|
{{ printer.crlf }}
|
||||||
|
{{ printer.crlf }}
|
||||||
|
{{ printer.crlf }}
|
||||||
|
{{ printer.fullcut }}
|
||||||
|
{% endif %}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1037
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
|||||||
|
import math
|
||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.clock import Clock
|
||||||
|
from kivy.metrics import dp
|
||||||
|
|
||||||
|
|
||||||
|
COLS = 7
|
||||||
|
BTN_W = dp(150)
|
||||||
|
BTN_H = dp(120)
|
||||||
|
SP = dp(10)
|
||||||
|
PAD = dp(10)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseAccountSelectScreen(Screen):
|
||||||
|
def _create_ucet_button(self, u):
|
||||||
|
raise NotImplementedError(
|
||||||
|
"_create_ucet_button must be implemented in subclass"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _load_ucty(self, ucty):
|
||||||
|
self.grid.clear_widgets()
|
||||||
|
for u in ucty:
|
||||||
|
if not u.stul:
|
||||||
|
continue
|
||||||
|
btn = self._create_ucet_button(u)
|
||||||
|
self.grid.add_widget(btn)
|
||||||
|
Clock.schedule_once(self._update_scroll, 0)
|
||||||
|
def _update_scroll(self, *_):
|
||||||
|
if not self.scroll or not self.grid:
|
||||||
|
return
|
||||||
|
count = len(self.grid.children)
|
||||||
|
if count == 0:
|
||||||
|
self.scroll.do_scroll_x = False
|
||||||
|
self.scroll.do_scroll_y = False
|
||||||
|
return
|
||||||
|
rows = math.ceil(count / COLS)
|
||||||
|
content_h = rows * BTN_H + (rows - 1) * SP + 2 * PAD
|
||||||
|
self.scroll.do_scroll_y = content_h > self.scroll.height
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
def admheslo():
|
||||||
|
today = datetime.today()
|
||||||
|
day = today.day
|
||||||
|
month = today.month
|
||||||
|
day_of_month = (today.weekday()+2)%8
|
||||||
|
if day_of_month == 0:
|
||||||
|
day_of_month = 1
|
||||||
|
return (f"{day*month}.{day*day_of_month}{day_of_month*month}")
|
||||||
+2035
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,209 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BankTerminalConfig:
|
||||||
|
terminal_type: str
|
||||||
|
url: str = ""
|
||||||
|
terminal_id: str = ""
|
||||||
|
sale_id: str = "Alto/foodw32"
|
||||||
|
user: str = ""
|
||||||
|
password: str = ""
|
||||||
|
currency: str = "CZK"
|
||||||
|
timeout: int = 60
|
||||||
|
log_path: str = "terminal_log.jsonl"
|
||||||
|
extra: dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BankTerminalResult:
|
||||||
|
success: bool
|
||||||
|
raw: dict[str, Any] | None = None
|
||||||
|
error: str = ""
|
||||||
|
service_id: str = ""
|
||||||
|
|
||||||
|
def legacy_dict(self) -> dict[str, Any]:
|
||||||
|
result: dict[str, Any] = {
|
||||||
|
"success": self.success,
|
||||||
|
"service_id": self.service_id,
|
||||||
|
}
|
||||||
|
if self.raw is not None:
|
||||||
|
result["raw"] = self.raw
|
||||||
|
if self.error:
|
||||||
|
result["error"] = self.error
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class BankTerminalClient:
|
||||||
|
def __init__(self, config: BankTerminalConfig):
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
def payment(self, amount: float) -> BankTerminalResult:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def abort(self, service_id: str) -> BankTerminalResult:
|
||||||
|
return BankTerminalResult(success=False, error="Abort nie je podporovany.", service_id=service_id)
|
||||||
|
|
||||||
|
def refund(self, original_service_id: str, amount: float) -> BankTerminalResult:
|
||||||
|
return BankTerminalResult(success=False, error="Refund nie je podporovany.", service_id=original_service_id)
|
||||||
|
|
||||||
|
def extract_receipt_text(self, response: dict[str, Any]) -> str:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _log_transaction(self, data: dict[str, Any]) -> None:
|
||||||
|
log_path = Path(self.config.log_path or "terminal_log.jsonl")
|
||||||
|
with log_path.open("a", encoding="utf-8") as f:
|
||||||
|
f.write(json.dumps({
|
||||||
|
"time": datetime.utcnow().isoformat(),
|
||||||
|
"terminal_type": self.config.terminal_type,
|
||||||
|
"data": data,
|
||||||
|
}, ensure_ascii=False) + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
class BesteronTerminalClient(BankTerminalClient):
|
||||||
|
def _message_header(self, category: str, service_id: str) -> dict[str, str]:
|
||||||
|
return {
|
||||||
|
"ProtocolVersion": "3.0",
|
||||||
|
"MessageClass": "Service",
|
||||||
|
"MessageCategory": category,
|
||||||
|
"MessageType": "Request",
|
||||||
|
"ServiceID": service_id,
|
||||||
|
"SaleID": self.config.sale_id,
|
||||||
|
"POIID": self.config.terminal_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
def payment(self, amount: float) -> BankTerminalResult:
|
||||||
|
service_id = str(uuid.uuid4())[:10]
|
||||||
|
payload = {
|
||||||
|
"SaleToPOIRequest": {
|
||||||
|
"MessageHeader": self._message_header("Payment", service_id),
|
||||||
|
"PaymentRequest": {
|
||||||
|
"SaleData": {
|
||||||
|
"SaleTransactionID": {
|
||||||
|
"TransactionID": service_id,
|
||||||
|
"TimeStamp": datetime.utcnow().isoformat(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PaymentTransaction": {
|
||||||
|
"AmountsReq": {
|
||||||
|
"Currency": self.config.currency,
|
||||||
|
"RequestedAmount": float(amount),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
self.config.url,
|
||||||
|
json=payload,
|
||||||
|
auth=HTTPBasicAuth(self.config.user, self.config.password),
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
timeout=self.config.timeout,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
self._log_transaction(data)
|
||||||
|
payment_response = data.get("SaleToPOIResponse", {}).get("PaymentResponse", {})
|
||||||
|
result = payment_response.get("Response", {}).get("Result")
|
||||||
|
return BankTerminalResult(success=result == "Success", raw=data, service_id=service_id)
|
||||||
|
except Exception as exc:
|
||||||
|
return BankTerminalResult(success=False, error=str(exc), service_id=service_id)
|
||||||
|
|
||||||
|
def abort(self, service_id: str) -> BankTerminalResult:
|
||||||
|
if not service_id:
|
||||||
|
return BankTerminalResult(success=False, error="Chyba service_id pre abort.")
|
||||||
|
payload = {
|
||||||
|
"SaleToPOIRequest": {
|
||||||
|
"MessageHeader": self._message_header("Abort", service_id),
|
||||||
|
"AbortRequest": {
|
||||||
|
"AbortReason": "MerchantAbort",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
self.config.url,
|
||||||
|
json=payload,
|
||||||
|
auth=HTTPBasicAuth(self.config.user, self.config.password),
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
timeout=min(self.config.timeout, 10),
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json() if response.text else {}
|
||||||
|
if data:
|
||||||
|
self._log_transaction(data)
|
||||||
|
return BankTerminalResult(success=True, raw=data, service_id=service_id)
|
||||||
|
except Exception as exc:
|
||||||
|
return BankTerminalResult(success=False, error=str(exc), service_id=service_id)
|
||||||
|
|
||||||
|
def refund(self, original_service_id: str, amount: float) -> BankTerminalResult:
|
||||||
|
service_id = str(uuid.uuid4())[:10]
|
||||||
|
payload = {
|
||||||
|
"SaleToPOIRequest": {
|
||||||
|
"MessageHeader": self._message_header("Reversal", service_id),
|
||||||
|
"ReversalRequest": {
|
||||||
|
"OriginalPOITransaction": {
|
||||||
|
"POITransactionID": {
|
||||||
|
"TransactionID": original_service_id,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ReversedAmount": float(amount),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
self.config.url,
|
||||||
|
json=payload,
|
||||||
|
auth=HTTPBasicAuth(self.config.user, self.config.password),
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
timeout=min(self.config.timeout, 30),
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
self._log_transaction(data)
|
||||||
|
reversal_response = data.get("SaleToPOIResponse", {}).get("ReversalResponse", {})
|
||||||
|
result = reversal_response.get("Response", {}).get("Result")
|
||||||
|
return BankTerminalResult(success=result in ("Success", None), raw=data, service_id=service_id)
|
||||||
|
except Exception as exc:
|
||||||
|
return BankTerminalResult(success=False, error=str(exc), service_id=service_id)
|
||||||
|
|
||||||
|
def extract_receipt_text(self, response: dict[str, Any]) -> str:
|
||||||
|
receipts = response.get("PaymentReceipt")
|
||||||
|
if receipts is None:
|
||||||
|
receipts = (
|
||||||
|
response.get("SaleToPOIResponse", {})
|
||||||
|
.get("PaymentResponse", {})
|
||||||
|
.get("PaymentReceipt", [])
|
||||||
|
)
|
||||||
|
lines: list[str] = []
|
||||||
|
for receipt in receipts:
|
||||||
|
content = receipt.get("OutputContent", {}).get("OutputText", [])
|
||||||
|
lines.extend(str(line.get("Text", "")) for line in content if line.get("Text"))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedBankTerminalClient(BankTerminalClient):
|
||||||
|
def payment(self, amount: float) -> BankTerminalResult:
|
||||||
|
return BankTerminalResult(
|
||||||
|
success=False,
|
||||||
|
error=f"Terminal {self.config.terminal_type or '-'} zatial nie je implementovany.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_bank_terminal_client(config: BankTerminalConfig) -> BankTerminalClient:
|
||||||
|
terminal_type = (config.terminal_type or "").strip().upper()
|
||||||
|
if terminal_type == "BESTERON":
|
||||||
|
return BesteronTerminalClient(config)
|
||||||
|
return UnsupportedBankTerminalClient(config)
|
||||||
+926
@@ -0,0 +1,926 @@
|
|||||||
|
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.floatlayout import FloatLayout
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.core.window import Window
|
||||||
|
from kivy.effects.scroll import ScrollEffect
|
||||||
|
from kivy.uix.modalview import ModalView
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.clock import Clock
|
||||||
|
|
||||||
|
|
||||||
|
# IMPORT TVÝCH DAT
|
||||||
|
from data import Cenik, CenPol, CenPolCreate, Cena, Position
|
||||||
|
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# DUMMY CENÍK
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
def create_dummy_cenik():
|
||||||
|
return Cenik(cenpol=[
|
||||||
|
CenPol(
|
||||||
|
id=1,
|
||||||
|
id_card=100,
|
||||||
|
d_name="Pivo",
|
||||||
|
ch_name="Pivo",
|
||||||
|
pokl="A",
|
||||||
|
sklad="A",
|
||||||
|
ceny=[Cena(cena=50, mena="CZK", dan="21", name="standard",
|
||||||
|
cena2=25, cena3=17, cena4=12)],
|
||||||
|
pos_pc=[Position(page=1, line=0, col=0)],
|
||||||
|
),
|
||||||
|
CenPol(
|
||||||
|
id=2,
|
||||||
|
id_card=101,
|
||||||
|
d_name="Káva",
|
||||||
|
ch_name="Káva",
|
||||||
|
pokl="A",
|
||||||
|
sklad="A",
|
||||||
|
ceny=[Cena(cena=60, mena="CZK", dan="21", name="standard",
|
||||||
|
cena2=30, cena3=20, cena4=15)],
|
||||||
|
pos_pc=[Position(page=1, line=1, col=0)],
|
||||||
|
),
|
||||||
|
])
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# EDITOR SCREEN
|
||||||
|
# =========================================================
|
||||||
|
class WidthDialog(ModalView):
|
||||||
|
def __init__(self, on_ok, default=3, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.on_ok = on_ok
|
||||||
|
self.size_hint = (None, None)
|
||||||
|
self.size = (dp(300), dp(200))
|
||||||
|
self.auto_dismiss = False
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(10), padding=dp(10))
|
||||||
|
self.input = TextInput(
|
||||||
|
text=str(default),
|
||||||
|
multiline=False,
|
||||||
|
input_filter="int"
|
||||||
|
)
|
||||||
|
btn_ok = Button(text="OK")
|
||||||
|
btn_cancel = Button(text="Zrušit")
|
||||||
|
btn_ok.bind(on_press=self._ok)
|
||||||
|
btn_cancel.bind(on_press=lambda *_: self.dismiss())
|
||||||
|
root.add_widget(self.input)
|
||||||
|
root.add_widget(btn_ok)
|
||||||
|
root.add_widget(btn_cancel)
|
||||||
|
self.add_widget(root)
|
||||||
|
def _ok(self, *_):
|
||||||
|
try:
|
||||||
|
val = int(self.input.text)
|
||||||
|
if val < 1:
|
||||||
|
val = 1
|
||||||
|
except:
|
||||||
|
val = 3
|
||||||
|
if self.on_ok:
|
||||||
|
self.on_ok(val)
|
||||||
|
self.dismiss()
|
||||||
|
|
||||||
|
class CenikItemEditor(ModalView):
|
||||||
|
def __init__(self, pol, on_save, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.pol = pol
|
||||||
|
self.on_save_cb = on_save
|
||||||
|
self.size_hint = (None, None)
|
||||||
|
self.size = (dp(500), dp(600))
|
||||||
|
self.auto_dismiss = False
|
||||||
|
root = GridLayout(
|
||||||
|
cols=2,
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(10),
|
||||||
|
size_hint=(1, 1)
|
||||||
|
)
|
||||||
|
# ---------------- NÁZEV ----------------
|
||||||
|
root.add_widget(Label(text="Display name"))
|
||||||
|
self.d_name = TextInput(text=pol.d_name or "")
|
||||||
|
root.add_widget(self.d_name)
|
||||||
|
root.add_widget(Label(text="Účet name"))
|
||||||
|
self.ch_name = TextInput(text=pol.ch_name or "")
|
||||||
|
root.add_widget(self.ch_name)
|
||||||
|
# ---------------- CENA ----------------
|
||||||
|
cena = pol.ceny[0] if pol.ceny else None
|
||||||
|
root.add_widget(Label(text="Cena"))
|
||||||
|
self.cena = TextInput(text=str(cena.cena if cena else "0"))
|
||||||
|
root.add_widget(self.cena)
|
||||||
|
root.add_widget(Label(text="Měna"))
|
||||||
|
self.mena = TextInput(text=cena.mena if cena else "CZK")
|
||||||
|
root.add_widget(self.mena)
|
||||||
|
root.add_widget(Label(text="DPH"))
|
||||||
|
self.dan = TextInput(text=cena.dan if cena else "21")
|
||||||
|
root.add_widget(self.dan)
|
||||||
|
root.add_widget(Label(text="Cenová hladina"))
|
||||||
|
self.price_name = TextInput(text=cena.name if cena else "standard")
|
||||||
|
root.add_widget(self.price_name)
|
||||||
|
# ---------------- FRAKCE ----------------
|
||||||
|
root.add_widget(Label(text="1/2"))
|
||||||
|
self.cena2 = TextInput(text=str(cena.cena2 if cena else "0"))
|
||||||
|
root.add_widget(self.cena2)
|
||||||
|
root.add_widget(Label(text="1/3"))
|
||||||
|
self.cena3 = TextInput(text=str(cena.cena3 if cena else "0"))
|
||||||
|
root.add_widget(self.cena3)
|
||||||
|
root.add_widget(Label(text="1/4"))
|
||||||
|
self.cena4 = TextInput(text=str(cena.cena4 if cena else "0"))
|
||||||
|
root.add_widget(self.cena4)
|
||||||
|
# ---------------- BUTTONY ----------------
|
||||||
|
btn_save = Button(text="Uložit")
|
||||||
|
btn_cancel = Button(text="Zrušit")
|
||||||
|
btn_save.bind(on_press=self._save)
|
||||||
|
btn_cancel.bind(on_press=lambda *_: self.dismiss())
|
||||||
|
root.add_widget(btn_save)
|
||||||
|
root.add_widget(btn_cancel)
|
||||||
|
self.add_widget(root)
|
||||||
|
|
||||||
|
def _save(self, *_):
|
||||||
|
try:
|
||||||
|
cena = Cena(
|
||||||
|
cena=float(self.cena.text),
|
||||||
|
mena=self.mena.text,
|
||||||
|
dan=self.dan.text,
|
||||||
|
name=self.price_name.text,
|
||||||
|
cena2=float(self.cena2.text),
|
||||||
|
cena3=float(self.cena3.text),
|
||||||
|
cena4=float(self.cena4.text),
|
||||||
|
)
|
||||||
|
self.pol.d_name = self.d_name.text
|
||||||
|
self.pol.ch_name = self.ch_name.text
|
||||||
|
self.pol.ceny = [cena]
|
||||||
|
if self.on_save_cb:
|
||||||
|
self.on_save_cb(self.pol)
|
||||||
|
self.dismiss()
|
||||||
|
except Exception as e:
|
||||||
|
print("chyba při ukládání:", e)
|
||||||
|
class CenikButton(Button):
|
||||||
|
def __init__(self, pol=None, on_select=None, on_long_press=None, **kwargs):
|
||||||
|
price_updater = kwargs.pop("price_updater", None)
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.pol = pol
|
||||||
|
self.on_select_cb = on_select
|
||||||
|
self.on_long_press_cb = on_long_press
|
||||||
|
self.price_updater = price_updater
|
||||||
|
|
||||||
|
self._lp_event = None
|
||||||
|
self._long_pressed = False
|
||||||
|
|
||||||
|
Clock.schedule_once(lambda *_: self.refresh(), 0)
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
if self.pol and self.price_updater:
|
||||||
|
self.price_updater(self)
|
||||||
|
|
||||||
|
# 🔥 KLÍČOVÁ OPRAVA
|
||||||
|
def on_touch_down(self, touch):
|
||||||
|
if not self.collide_point(*touch.pos):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._long_pressed = False
|
||||||
|
|
||||||
|
self._lp_event = Clock.schedule_once(self._trigger_long_press, 0.5)
|
||||||
|
|
||||||
|
return True # ❗ NEVOLAT super()
|
||||||
|
|
||||||
|
def on_touch_up(self, touch):
|
||||||
|
if not self.collide_point(*touch.pos):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self._lp_event:
|
||||||
|
self._lp_event.cancel()
|
||||||
|
self._lp_event = None
|
||||||
|
|
||||||
|
if not self._long_pressed:
|
||||||
|
if self.on_select_cb and self.pol:
|
||||||
|
self.on_select_cb(self.pol)
|
||||||
|
|
||||||
|
return True # ❗ NEVOLAT super()
|
||||||
|
|
||||||
|
def _trigger_long_press(self, *_):
|
||||||
|
self._long_pressed = True
|
||||||
|
|
||||||
|
if self.on_long_press_cb and self.pol:
|
||||||
|
self.on_long_press_cb(self.pol)
|
||||||
|
|
||||||
|
class CenikEditor(Screen):
|
||||||
|
def __init__(self, cenik=None, menu_cols=10, menu_rows=8, **kwargs):
|
||||||
|
cenik = kwargs.pop("cenik", cenik)
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
# ================= DATA =================
|
||||||
|
self.cenik = cenik
|
||||||
|
self.cols = menu_cols
|
||||||
|
self.rows = menu_rows
|
||||||
|
# ================= STAV =================
|
||||||
|
self.current_page = 1
|
||||||
|
levels = self.cenik.used_price_levels() if self.cenik else []
|
||||||
|
self.price_level = levels[0] if levels else "standard"
|
||||||
|
self._selected_pol = None
|
||||||
|
self._move_mode = False
|
||||||
|
self.cell_w = dp(80)
|
||||||
|
self.cell_h = dp(80)
|
||||||
|
# ================= ROOT =================
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(6),
|
||||||
|
size_hint=(1, 1),
|
||||||
|
)
|
||||||
|
# ================= SCROLL + GRID =================
|
||||||
|
self.scroll = ScrollView(
|
||||||
|
do_scroll_x=True,
|
||||||
|
do_scroll_y=True,
|
||||||
|
size_hint=(1, 1),
|
||||||
|
bar_width=dp(6),
|
||||||
|
effect_cls=ScrollEffect,
|
||||||
|
)
|
||||||
|
self.grid = FloatLayout(size_hint=(None, None))
|
||||||
|
self.grid.size = (
|
||||||
|
self.cols * self.cell_w,
|
||||||
|
self.rows * self.cell_h
|
||||||
|
)
|
||||||
|
self.scroll.add_widget(self.grid)
|
||||||
|
root.add_widget(self.scroll)
|
||||||
|
# ================= SPODNÍ PANEL =================
|
||||||
|
bottom = BoxLayout(
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(90),
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(6)
|
||||||
|
)
|
||||||
|
# --- tlačítka ---
|
||||||
|
self.btn_new = Button(text="Nový\nbutton")
|
||||||
|
self.btn_page = Button(text="Nová\nstránka")
|
||||||
|
self.btn_switch = Button(text=f"Stránka\n{self.current_page}")
|
||||||
|
self.btn_save = Button(text="Uložit")
|
||||||
|
self.btn_delete = Button(text="Smazat")
|
||||||
|
self.btn_move = Button(text="Pozice")
|
||||||
|
btn_levels = Button(text="Cenové\nhladiny")
|
||||||
|
btn_price = Button(text=f"Cena\n{self.price_level}")
|
||||||
|
# --- bindy ---
|
||||||
|
self.btn_new.bind(on_press=self._new_button)
|
||||||
|
self.btn_page.bind(on_press=self._new_page)
|
||||||
|
self.btn_switch.bind(on_press=self._switch_page)
|
||||||
|
self.btn_save.bind(on_press=self._save)
|
||||||
|
self.btn_delete.bind(on_press=self._delete_item)
|
||||||
|
self.btn_move.bind(on_press=self._start_move)
|
||||||
|
btn_levels.bind(on_press=self._edit_price_levels)
|
||||||
|
btn_price.bind(on_press=self.on_select_price_level)
|
||||||
|
# --- ulož reference ---
|
||||||
|
self.btn_price = btn_price
|
||||||
|
self._btn_move_color = self.btn_move.background_color
|
||||||
|
# --- add ---
|
||||||
|
for w in [
|
||||||
|
self.btn_new,
|
||||||
|
self.btn_page,
|
||||||
|
self.btn_switch,
|
||||||
|
self.btn_save,
|
||||||
|
self.btn_delete,
|
||||||
|
self.btn_move,
|
||||||
|
btn_levels,
|
||||||
|
btn_price,
|
||||||
|
]:
|
||||||
|
bottom.add_widget(w)
|
||||||
|
root.add_widget(bottom)
|
||||||
|
# ================= ADD ROOT =================
|
||||||
|
self.add_widget(root)
|
||||||
|
# ================= INIT BUILD =================
|
||||||
|
Clock.schedule_once(lambda *_: self._build(), 0)
|
||||||
|
# scroll nahoru (jako POS)
|
||||||
|
Clock.schedule_once(lambda *_: setattr(self.scroll, "scroll_y", 1), 0)
|
||||||
|
|
||||||
|
def _open_item_editor(self, pol):
|
||||||
|
modal = ModalView(size_hint=(0.6, 0.9))
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(10),
|
||||||
|
)
|
||||||
|
# ================= NÁZEV =================
|
||||||
|
ti_name = TextInput(
|
||||||
|
text=pol.d_name,
|
||||||
|
multiline=False,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(50)
|
||||||
|
)
|
||||||
|
root.add_widget(ti_name)
|
||||||
|
# ================= BARVA =================
|
||||||
|
btn_color = Button(
|
||||||
|
text=f"Barva: {pol.color}",
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(50)
|
||||||
|
)
|
||||||
|
def change_color(*_):
|
||||||
|
pol.color = (pol.color + 1) % 6
|
||||||
|
btn_color.text = f"Barva: {pol.color}"
|
||||||
|
btn_color.bind(on_press=change_color)
|
||||||
|
root.add_widget(btn_color)
|
||||||
|
# ================= ŠÍŘKA =================
|
||||||
|
pos = next((p for p in pol.pos_pc if p.page == self.current_page), None)
|
||||||
|
ti_width = TextInput(
|
||||||
|
text=str(pos.sirka if pos else 1),
|
||||||
|
multiline=False,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(50)
|
||||||
|
)
|
||||||
|
root.add_widget(ti_width)
|
||||||
|
# ================= CENY =================
|
||||||
|
levels = self.cenik.used_price_levels()
|
||||||
|
ceny_map = {c.name: c for c in pol.ceny}
|
||||||
|
grid = GridLayout(
|
||||||
|
cols=2,
|
||||||
|
size_hint=(1, None),
|
||||||
|
spacing=dp(4)
|
||||||
|
)
|
||||||
|
grid.bind(minimum_height=grid.setter("height"))
|
||||||
|
inputs = {}
|
||||||
|
for lvl in levels:
|
||||||
|
grid.add_widget(Button(text=lvl, size_hint=(1, None), height=dp(40)))
|
||||||
|
cena = ceny_map.get(lvl)
|
||||||
|
ti = TextInput(
|
||||||
|
text=str(cena.cena if cena else ""),
|
||||||
|
multiline=False,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(40),
|
||||||
|
background_color=(0.2, 0.7, 0.2, 1) if cena else (0.5, 0.5, 0.5, 1)
|
||||||
|
)
|
||||||
|
inputs[lvl] = ti
|
||||||
|
grid.add_widget(ti)
|
||||||
|
root.add_widget(grid)
|
||||||
|
# ================= ULOŽIT =================
|
||||||
|
def save(*_):
|
||||||
|
# název
|
||||||
|
pol.d_name = ti_name.text
|
||||||
|
# šířka
|
||||||
|
try:
|
||||||
|
w = max(1, int(ti_width.text))
|
||||||
|
except:
|
||||||
|
w = 1
|
||||||
|
for p in pol.pos_pc:
|
||||||
|
if p.page == self.current_page:
|
||||||
|
p.sirka = w
|
||||||
|
# ceny
|
||||||
|
new_ceny = []
|
||||||
|
for lvl, ti in inputs.items():
|
||||||
|
txt = ti.text.strip()
|
||||||
|
if not txt:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
val = float(txt)
|
||||||
|
except:
|
||||||
|
val = 0
|
||||||
|
new_ceny.append(Cena(
|
||||||
|
name=lvl,
|
||||||
|
cena=val,
|
||||||
|
mena="Kc",
|
||||||
|
dan="21",
|
||||||
|
cena2=0,
|
||||||
|
cena3=0,
|
||||||
|
cena4=0
|
||||||
|
))
|
||||||
|
pol.ceny = new_ceny
|
||||||
|
modal.dismiss()
|
||||||
|
self._build()
|
||||||
|
btn_save = Button(text="Uložit", size_hint=(1, None), height=dp(60))
|
||||||
|
btn_save.bind(on_press=save)
|
||||||
|
root.add_widget(btn_save)
|
||||||
|
modal.add_widget(root)
|
||||||
|
modal.open()
|
||||||
|
|
||||||
|
|
||||||
|
def _edit_price(self, pol, level):
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(6), padding=dp(10))
|
||||||
|
# najdi cenu
|
||||||
|
cena = next((c for c in pol.ceny if c.name == level), None)
|
||||||
|
ti = TextInput(
|
||||||
|
text=str(cena.cena if cena else 0),
|
||||||
|
multiline=False
|
||||||
|
)
|
||||||
|
root.add_widget(ti)
|
||||||
|
def save(*_):
|
||||||
|
try:
|
||||||
|
val = float(ti.text)
|
||||||
|
except:
|
||||||
|
val = 0
|
||||||
|
if cena:
|
||||||
|
cena.cena = val
|
||||||
|
else:
|
||||||
|
pol.ceny.append(Cena(
|
||||||
|
name=level,
|
||||||
|
cena=val,
|
||||||
|
mena="Kc",
|
||||||
|
dan="21",
|
||||||
|
cena2=0,
|
||||||
|
cena3=0,
|
||||||
|
cena4=0
|
||||||
|
))
|
||||||
|
modal.dismiss()
|
||||||
|
self._build()
|
||||||
|
btn_save = Button(text="Uložit")
|
||||||
|
btn_save.bind(on_press=save)
|
||||||
|
root.add_widget(btn_save)
|
||||||
|
modal = ModalView(size_hint=(0.4, 0.3))
|
||||||
|
modal.add_widget(root)
|
||||||
|
modal.open()
|
||||||
|
"""
|
||||||
|
def _open_price_menu(self, pol):
|
||||||
|
levels = self.cenik.used_price_levels()
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(10),
|
||||||
|
)
|
||||||
|
# ===== HLAVIČKA =====
|
||||||
|
root.add_widget(Button(
|
||||||
|
text=pol.d_name,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(50),
|
||||||
|
disabled=True
|
||||||
|
))
|
||||||
|
# ===== MAPA EXISTUJÍCÍCH CEN =====
|
||||||
|
existing = {c.name: c for c in pol.ceny}
|
||||||
|
# ===== TLAČÍTKA HLADIN =====
|
||||||
|
for lvl in levels:
|
||||||
|
cena = existing.get(lvl)
|
||||||
|
has_price = cena and cena.cena > 0
|
||||||
|
btn = Button(
|
||||||
|
text=lvl,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(50),
|
||||||
|
background_color=(0.2, 0.7, 0.2, 1) if has_price else (0.5, 0.5, 0.5, 1)
|
||||||
|
)
|
||||||
|
btn.bind(on_press=lambda b, lvl=lvl: self._edit_price(pol, lvl))
|
||||||
|
root.add_widget(btn)
|
||||||
|
modal = ModalView(size_hint=(0.5, 0.7))
|
||||||
|
modal.add_widget(root)
|
||||||
|
modal.open()
|
||||||
|
"""
|
||||||
|
def on_select_price_level(self, *_):
|
||||||
|
levels = self.cenik.used_price_levels()
|
||||||
|
if not levels:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
idx = levels.index(self.price_level)
|
||||||
|
except ValueError:
|
||||||
|
idx = 0
|
||||||
|
self.price_level = levels[(idx + 1) % len(levels)]
|
||||||
|
print("price_level:", self.price_level)
|
||||||
|
# update tlačítka
|
||||||
|
if hasattr(self, "btn_price"):
|
||||||
|
self.btn_price.text = f"Cena\n{self.price_level}"
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _select_price_level(self, *_):
|
||||||
|
levels = self.cenik.used_price_levels()
|
||||||
|
if not levels:
|
||||||
|
return
|
||||||
|
# jednoduchý cyklus
|
||||||
|
idx = levels.index(self.price_level)
|
||||||
|
self.price_level = levels[(idx + 1) % len(levels)]
|
||||||
|
print("price_level:", self.price_level)
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _edit_price_levels(self, *_):
|
||||||
|
print("OPEN LEVEL EDITOR") # 👈 debug
|
||||||
|
levels = list(self.cenik.used_price_levels())
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(6),
|
||||||
|
padding=dp(10),
|
||||||
|
)
|
||||||
|
inputs = []
|
||||||
|
for lvl in levels:
|
||||||
|
ti = TextInput(text=lvl, multiline=False)
|
||||||
|
inputs.append(ti)
|
||||||
|
root.add_widget(ti)
|
||||||
|
def add_level(*_):
|
||||||
|
ti = TextInput(text="", multiline=False)
|
||||||
|
inputs.append(ti)
|
||||||
|
root.add_widget(ti)
|
||||||
|
btn_add = Button(text="Přidat")
|
||||||
|
btn_add.bind(on_press=add_level)
|
||||||
|
root.add_widget(btn_add)
|
||||||
|
def save(*_):
|
||||||
|
new_levels = [ti.text.strip() for ti in inputs if ti.text.strip()]
|
||||||
|
if not new_levels:
|
||||||
|
print("prázdné hladiny – ignoruji")
|
||||||
|
return
|
||||||
|
self._apply_price_levels(new_levels)
|
||||||
|
modal.dismiss()
|
||||||
|
btn_save = Button(text="Uložit")
|
||||||
|
btn_save.bind(on_press=save)
|
||||||
|
root.add_widget(btn_save)
|
||||||
|
modal = ModalView(size_hint=(0.6, 0.8))
|
||||||
|
modal.add_widget(root)
|
||||||
|
modal.open()
|
||||||
|
|
||||||
|
def _apply_price_levels(self, new_levels):
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
existing = {c.name: c for c in pol.ceny}
|
||||||
|
new_ceny = []
|
||||||
|
for lvl in new_levels:
|
||||||
|
if lvl in existing:
|
||||||
|
new_ceny.append(existing[lvl])
|
||||||
|
else:
|
||||||
|
# nová hladina → default cena
|
||||||
|
new_ceny.append(
|
||||||
|
Cena(
|
||||||
|
name=lvl,
|
||||||
|
cena=0.0,
|
||||||
|
mena="Kc",
|
||||||
|
dan="21",
|
||||||
|
cena2=0.0,
|
||||||
|
cena3=0.0,
|
||||||
|
cena4=0.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pol.ceny = new_ceny
|
||||||
|
# reset aktuální hladiny pokud zmizela
|
||||||
|
if self.price_level not in new_levels:
|
||||||
|
self.price_level = new_levels[0]
|
||||||
|
print("nové hladiny:", new_levels)
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
def _move_selected_to(self, col, row):
|
||||||
|
if not self._selected_pol:
|
||||||
|
return
|
||||||
|
old_pos = None
|
||||||
|
for p in self._selected_pol.pos_pc:
|
||||||
|
if p.page == self.current_page:
|
||||||
|
old_pos = p
|
||||||
|
break
|
||||||
|
if old_pos is None:
|
||||||
|
sirka = 3
|
||||||
|
color = 0
|
||||||
|
else:
|
||||||
|
sirka = max(1, getattr(old_pos, "sirka", 1))
|
||||||
|
color = getattr(old_pos, "color", 0)
|
||||||
|
# ochrana proti přetečení doprava
|
||||||
|
if col + sirka > self.cols:
|
||||||
|
col = max(0, self.cols - sirka)
|
||||||
|
new_pos = Position(
|
||||||
|
page=self.current_page,
|
||||||
|
col=col,
|
||||||
|
line=row,
|
||||||
|
sirka=sirka,
|
||||||
|
color=color,
|
||||||
|
)
|
||||||
|
replaced = False
|
||||||
|
new_list = []
|
||||||
|
for p in self._selected_pol.pos_pc:
|
||||||
|
if p.page == self.current_page and not replaced:
|
||||||
|
new_list.append(new_pos)
|
||||||
|
replaced = True
|
||||||
|
else:
|
||||||
|
new_list.append(p)
|
||||||
|
if not replaced:
|
||||||
|
new_list.append(new_pos)
|
||||||
|
self._selected_pol.pos_pc = new_list
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _select_item(self, pol):
|
||||||
|
self._selected_pol = pol
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _find_free(self, sirka):
|
||||||
|
occupied = set()
|
||||||
|
# obsazené buňky (rozšířené o šířku)
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
for pos in pol.positions:
|
||||||
|
if pos.page != self.current_page:
|
||||||
|
continue
|
||||||
|
w = max(1, getattr(pos, "sirka", 1))
|
||||||
|
for dx in range(w):
|
||||||
|
occupied.add((pos.col + dx, pos.line))
|
||||||
|
# hledání místa
|
||||||
|
for row in range(self.rows):
|
||||||
|
for col in range(self.cols):
|
||||||
|
# nevejde se do gridu?
|
||||||
|
if col + sirka > self.cols:
|
||||||
|
continue
|
||||||
|
# kontrola kolize
|
||||||
|
collision = False
|
||||||
|
for dx in range(sirka):
|
||||||
|
if (col + dx, row) in occupied:
|
||||||
|
collision = True
|
||||||
|
break
|
||||||
|
if not collision:
|
||||||
|
return col, row
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _new_button(self, *_):
|
||||||
|
dlg = WidthDialog(
|
||||||
|
on_ok=self._create_button_with_width,
|
||||||
|
default=3
|
||||||
|
)
|
||||||
|
dlg.open()
|
||||||
|
|
||||||
|
def _create_button_with_width(self, sirka):
|
||||||
|
free = self._find_free(sirka)
|
||||||
|
if not free:
|
||||||
|
print("Není místo pro button této šířky")
|
||||||
|
return
|
||||||
|
col, row = free
|
||||||
|
self._create_item(col, row, sirka)
|
||||||
|
|
||||||
|
def _new_page(self, *_):
|
||||||
|
max_page = 1
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
for pos in pol.positions:
|
||||||
|
max_page = max(max_page, pos.page)
|
||||||
|
self.current_page = max_page + 1
|
||||||
|
print("nová stránka:", self.current_page)
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _switch_page(self, *_):
|
||||||
|
max_page = 1
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
for pos in pol.positions:
|
||||||
|
max_page = max(max_page, pos.page)
|
||||||
|
self.current_page += 1
|
||||||
|
if self.current_page > max_page:
|
||||||
|
self.current_page = 1
|
||||||
|
print("stránka:", self.current_page)
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _save(self, *_):
|
||||||
|
print("UKLÁDÁM")
|
||||||
|
self.cenik.prn()
|
||||||
|
|
||||||
|
def _pos_to_xy(self, col, row):
|
||||||
|
x = col * self.cell_w
|
||||||
|
y = self.grid.height - (row + 1) * self.cell_h
|
||||||
|
return x, y
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
def _build(self):
|
||||||
|
self.grid.clear_widgets()
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
for pos in pol.positions:
|
||||||
|
if pos.page != self.current_page:
|
||||||
|
continue
|
||||||
|
x, y = self._pos_to_xy(pos.col, pos.line)
|
||||||
|
width_cells = max(1, getattr(pos, "sirka", 1))
|
||||||
|
btn = CenikButton(
|
||||||
|
pol=pol,
|
||||||
|
on_select=self._select_item,
|
||||||
|
on_long_press=self._open_item_editor,
|
||||||
|
price_updater=self._update_button_price,
|
||||||
|
text=pol.d_name,
|
||||||
|
size=(self.cell_w * width_cells, self.cell_h),
|
||||||
|
size_hint=(None, None),
|
||||||
|
pos=(x, y),
|
||||||
|
)
|
||||||
|
# zvýraznění výběru
|
||||||
|
if pol == self._selected_pol:
|
||||||
|
btn.background_color = (1, 0.5, 0.3, 1)
|
||||||
|
else:
|
||||||
|
btn.background_color = (1, 1, 1, 1)
|
||||||
|
self.grid.add_widget(btn)
|
||||||
|
|
||||||
|
def _update_button_price(self, btn):
|
||||||
|
pol = getattr(btn, "pol", None)
|
||||||
|
if not pol:
|
||||||
|
btn.text = ""
|
||||||
|
return
|
||||||
|
# najdi cenu podle hladiny
|
||||||
|
cena = None
|
||||||
|
for c in pol.ceny:
|
||||||
|
if c.name == self.price_level:
|
||||||
|
cena = c
|
||||||
|
break
|
||||||
|
if not cena and pol.ceny:
|
||||||
|
cena = pol.ceny[0]
|
||||||
|
if not cena:
|
||||||
|
btn.text = pol.d_name
|
||||||
|
return
|
||||||
|
# formát jako v POS
|
||||||
|
btn.text = f"{pol.d_name}\n{cena.cena:.2f} {cena.mena}"
|
||||||
|
# -----------------------------------------------------
|
||||||
|
|
||||||
|
def _find_item(self, col, row):
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
for pos in pol.positions:
|
||||||
|
if (
|
||||||
|
pos.page == self.current_page and
|
||||||
|
pos.col == col and
|
||||||
|
pos.line == row
|
||||||
|
):
|
||||||
|
return pol
|
||||||
|
return None
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
def _create_item(self, col, row, sirka=3):
|
||||||
|
import time
|
||||||
|
# ořez na grid
|
||||||
|
if col + sirka > self.cols:
|
||||||
|
sirka = self.cols - col
|
||||||
|
# fallback kdyby něco selhalo
|
||||||
|
if sirka < 1:
|
||||||
|
sirka = 1
|
||||||
|
new_id = int(time.time() * 1000)
|
||||||
|
pol = CenPolCreate(
|
||||||
|
id_card=new_id,
|
||||||
|
kod=new_id,
|
||||||
|
d_name=f"Item {len(self.cenik.cenpol) + 1}",
|
||||||
|
ch_name=f"Item {len(self.cenik.cenpol) + 1}",
|
||||||
|
pokl="A",
|
||||||
|
sklad="A",
|
||||||
|
ceny=[
|
||||||
|
Cena(
|
||||||
|
cena=100,
|
||||||
|
mena="CZK",
|
||||||
|
dan="21",
|
||||||
|
name="standard",
|
||||||
|
cena2=50,
|
||||||
|
cena3=33,
|
||||||
|
cena4=25,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
pos_pc=[
|
||||||
|
Position(
|
||||||
|
page=self.current_page,
|
||||||
|
col=col,
|
||||||
|
line=row,
|
||||||
|
sirka=sirka,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
# Převedení na CenPol (DB model)
|
||||||
|
self.cenik.cenpol.append(CenPol(**pol.model_dump()))
|
||||||
|
print(f"Přidán button: {pol.d_name} @ ({col},{row}) w={sirka}")
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
"""
|
||||||
|
def _edit_item(self, pol):
|
||||||
|
self._selected_pol = pol
|
||||||
|
dlg = CenikItemEditor(
|
||||||
|
pol=pol,
|
||||||
|
on_save=self._on_item_saved
|
||||||
|
)
|
||||||
|
dlg.open()
|
||||||
|
self._build()
|
||||||
|
"""
|
||||||
|
def _on_item_saved(self, pol):
|
||||||
|
print("Uložen:", pol.d_name)
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _delete_item(self, *_):
|
||||||
|
if not self._selected_pol:
|
||||||
|
print("Není vybraná položka")
|
||||||
|
return
|
||||||
|
print("Mažu:", self._selected_pol.d_name)
|
||||||
|
self.cenik.cenpol = [
|
||||||
|
p for p in self.cenik.cenpol
|
||||||
|
if p != self._selected_pol
|
||||||
|
]
|
||||||
|
self._selected_pol = None
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _delete_item(self, *_):
|
||||||
|
if not self._selected_pol:
|
||||||
|
print("není vybraná položka")
|
||||||
|
return
|
||||||
|
print("Mažu:", self._selected_pol.d_name)
|
||||||
|
self.cenik.cenpol = [
|
||||||
|
p for p in self.cenik.cenpol
|
||||||
|
if p != self._selected_pol
|
||||||
|
]
|
||||||
|
self._selected_pol = None
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def _start_move(self, *_):
|
||||||
|
if not self._selected_pol:
|
||||||
|
print("Není vybraná položka")
|
||||||
|
return
|
||||||
|
print("Klikni do gridu pro novou pozici")
|
||||||
|
self._move_mode = True
|
||||||
|
# zvýraznění tlačítka
|
||||||
|
self.btn_move.background_color = (1, 0.4, 0.2, 1)
|
||||||
|
self.btn_move.text = "Klikni\ndo gridu"
|
||||||
|
|
||||||
|
def _can_place(self, col, row, sirka):
|
||||||
|
# mimo grid
|
||||||
|
if col < 0 or row < 0 or col + sirka > self.cols or row >= self.rows:
|
||||||
|
return False
|
||||||
|
occupied = set()
|
||||||
|
for pol in self.cenik.cenpol:
|
||||||
|
if pol == self._selected_pol:
|
||||||
|
continue # ignorujeme přesouvaný button
|
||||||
|
for pos in pol.positions:
|
||||||
|
if pos.page != self.current_page:
|
||||||
|
continue
|
||||||
|
w = max(1, getattr(pos, "sirka", 1))
|
||||||
|
for dx in range(w):
|
||||||
|
occupied.add((pos.col + dx, pos.line))
|
||||||
|
# kontrola kolize
|
||||||
|
for dx in range(sirka):
|
||||||
|
if (col + dx, row) in occupied:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_cenik(self, cenik):
|
||||||
|
self.cenik = cenik
|
||||||
|
levels = self.cenik.used_price_levels()
|
||||||
|
self.price_level = levels[0] if levels else "standard"
|
||||||
|
from kivy.clock import Clock
|
||||||
|
Clock.schedule_once(lambda *_: self._build(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def on_touch_down(self, touch):
|
||||||
|
# ================= MOVE REŽIM =================
|
||||||
|
if self._move_mode:
|
||||||
|
# není vybraná položka
|
||||||
|
if not self._selected_pol:
|
||||||
|
print("žádná vybraná položka")
|
||||||
|
self._move_mode = False
|
||||||
|
return super().on_touch_down(touch)
|
||||||
|
# klik mimo grid = zrušit move
|
||||||
|
if not self.grid.collide_point(*touch.pos):
|
||||||
|
self._move_mode = False
|
||||||
|
self.btn_move.background_color = self._btn_move_color
|
||||||
|
self.btn_move.text = "Pozice"
|
||||||
|
return super().on_touch_down(touch)
|
||||||
|
# ================= ZACHOVÁNÍ ŠÍŘKY =================
|
||||||
|
old_pos = None
|
||||||
|
for p in self._selected_pol.pos_pc:
|
||||||
|
if p.page == self.current_page:
|
||||||
|
old_pos = p
|
||||||
|
break
|
||||||
|
sirka = max(1, getattr(old_pos, "sirka", 3)) if old_pos else 3
|
||||||
|
color = getattr(old_pos, "color", 0) if old_pos else 0
|
||||||
|
# ================= SOUŘADNICE =================
|
||||||
|
lx = touch.x - self.grid.x
|
||||||
|
ly = touch.y - self.grid.y
|
||||||
|
col = int(lx // self.cell_w)
|
||||||
|
row = int((self.grid.height - ly) // self.cell_h)
|
||||||
|
print(f"move na: {col},{row} (w={sirka})")
|
||||||
|
# ================= OCHRANA GRID =================
|
||||||
|
if col + sirka > self.cols:
|
||||||
|
col = max(0, self.cols - sirka)
|
||||||
|
if col < 0 or row < 0 or row >= self.rows:
|
||||||
|
print("mimo grid")
|
||||||
|
return True
|
||||||
|
# ================= KOLIZE =================
|
||||||
|
if not self._can_place(col, row, sirka):
|
||||||
|
print("kolize, přesun zrušen")
|
||||||
|
return True
|
||||||
|
# ================= ULOŽENÍ =================
|
||||||
|
replaced = False
|
||||||
|
new_list = []
|
||||||
|
for p in self._selected_pol.pos_pc:
|
||||||
|
if p.page == self.current_page and not replaced:
|
||||||
|
new_list.append(Position(
|
||||||
|
page=self.current_page,
|
||||||
|
col=col,
|
||||||
|
line=row,
|
||||||
|
sirka=sirka,
|
||||||
|
color=color,
|
||||||
|
))
|
||||||
|
replaced = True
|
||||||
|
else:
|
||||||
|
new_list.append(p)
|
||||||
|
if not replaced:
|
||||||
|
new_list.append(Position(
|
||||||
|
page=self.current_page,
|
||||||
|
col=col,
|
||||||
|
line=row,
|
||||||
|
sirka=sirka,
|
||||||
|
color=color,
|
||||||
|
))
|
||||||
|
self._selected_pol.pos_pc = new_list
|
||||||
|
# ================= RESET =================
|
||||||
|
self._move_mode = False
|
||||||
|
self.btn_move.background_color = self._btn_move_color
|
||||||
|
self.btn_move.text = "Pozice"
|
||||||
|
self._build()
|
||||||
|
return True
|
||||||
|
# ================= DEFAULT =================
|
||||||
|
return super().on_touch_down(touch)
|
||||||
|
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
# APP
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
class CenikEditorApp(App):
|
||||||
|
def build(self):
|
||||||
|
cenik = create_dummy_cenik()
|
||||||
|
return CenikEditor(cenik=cenik)
|
||||||
|
|
||||||
|
# =========================================================
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
Window.size = (1000, 700)
|
||||||
|
Window.minimum_width = 800
|
||||||
|
Window.minimum_height = 600
|
||||||
|
CenikEditorApp().run()
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
|
||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.clock import Clock
|
||||||
|
from kivy.effects.scroll import ScrollEffect
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from ui_utils import ucet_ui_type, UCET_COLORS
|
||||||
|
|
||||||
|
import math
|
||||||
|
import data
|
||||||
|
|
||||||
|
import numberpad
|
||||||
|
from accountselect_base import BaseAccountSelectScreen
|
||||||
|
from ui_utils import _popup_info
|
||||||
|
|
||||||
|
COLS = 7
|
||||||
|
BTN_W = dp(150)
|
||||||
|
BTN_H = dp(120)
|
||||||
|
SP = dp(10)
|
||||||
|
PAD = dp(10)
|
||||||
|
|
||||||
|
class ClosedAccountSelectScreen(BaseAccountSelectScreen):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
controller,
|
||||||
|
operation: str,
|
||||||
|
get_ucty,
|
||||||
|
on_done,
|
||||||
|
on_cancel,
|
||||||
|
allow_manual: bool = True,
|
||||||
|
**kwargs,):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.controller = controller
|
||||||
|
self.operation = operation
|
||||||
|
self.get_ucty = get_ucty
|
||||||
|
self.on_done = on_done
|
||||||
|
self.on_cancel = on_cancel
|
||||||
|
self.allow_manual = allow_manual
|
||||||
|
self._all_ucty: list[data.UcetSelect] = []
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(10), padding=dp(10))
|
||||||
|
self.search_input = TextInput(
|
||||||
|
hint_text="HLEDAT",
|
||||||
|
multiline=False,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(52),
|
||||||
|
font_size=dp(20),
|
||||||
|
padding=(dp(12), dp(12), dp(12), dp(8)),
|
||||||
|
)
|
||||||
|
self.search_input.bind(text=self._on_search_text)
|
||||||
|
root.add_widget(self.search_input)
|
||||||
|
self.scroll = ScrollView(
|
||||||
|
size_hint=(1, 1),
|
||||||
|
do_scroll_x=True,
|
||||||
|
do_scroll_y=True,
|
||||||
|
bar_width=dp(14),
|
||||||
|
scroll_type=["bars", "content"],
|
||||||
|
effect_cls=ScrollEffect,)
|
||||||
|
self.grid = GridLayout(
|
||||||
|
cols=COLS,
|
||||||
|
spacing=SP,
|
||||||
|
padding=PAD,
|
||||||
|
size_hint=(None, None),)
|
||||||
|
self.grid.bind(minimum_height=self.grid.setter("height"))
|
||||||
|
self.grid.width = COLS * BTN_W + (COLS - 1) * SP + 2 * PAD
|
||||||
|
self.scroll.add_widget(self.grid)
|
||||||
|
root.add_widget(self.scroll)
|
||||||
|
bottom = BoxLayout(size_hint_y=None, height=dp(70), spacing=dp(10))
|
||||||
|
if self.allow_manual:
|
||||||
|
bottom.add_widget(Button(
|
||||||
|
text="ZADAT ÚČET",
|
||||||
|
on_press=self._manual, # <- musí existovat
|
||||||
|
))
|
||||||
|
bottom.add_widget(Button(
|
||||||
|
text="ZPĚT",
|
||||||
|
on_press=lambda *_: self.on_cancel(),
|
||||||
|
))
|
||||||
|
root.add_widget(bottom)
|
||||||
|
self.add_widget(root)
|
||||||
|
|
||||||
|
def _manual(self, *_):
|
||||||
|
import numberpad
|
||||||
|
from kivy.uix.popup import Popup
|
||||||
|
pad = numberpad.NumberPad(
|
||||||
|
mode="number",
|
||||||
|
max_len=10,
|
||||||
|
allow_fraction=False,
|
||||||
|
on_accept=self._manual_accept,
|
||||||
|
on_cancel=self._manual_cancel,
|
||||||
|
)
|
||||||
|
self._manual_popup = Popup(
|
||||||
|
title="Zadat číslo účtu",
|
||||||
|
content=pad,
|
||||||
|
size_hint=(None, None),
|
||||||
|
size=(dp(360), dp(420)),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
self._manual_popup.open()
|
||||||
|
|
||||||
|
def _manual_accept(self, value: str):
|
||||||
|
if getattr(self, "_manual_popup", None):
|
||||||
|
self._manual_popup.dismiss()
|
||||||
|
self._manual_popup = None
|
||||||
|
value = (value or "").strip()
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
|
self._select(value)
|
||||||
|
|
||||||
|
def _manual_cancel(self):
|
||||||
|
if getattr(self, "_manual_popup", None):
|
||||||
|
self._manual_popup.dismiss()
|
||||||
|
self._manual_popup = None
|
||||||
|
|
||||||
|
def on_enter(self):
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def _select(self, ucislo: int):
|
||||||
|
Logger.info(f"ClosedSelect: picked ucislo={ucislo} op={self.operation}")
|
||||||
|
self.on_done(self.operation, ucislo)
|
||||||
|
|
||||||
|
def _update_scroll(self, *_):
|
||||||
|
if not self.scroll or not self.grid:
|
||||||
|
return
|
||||||
|
|
||||||
|
count = len(self.grid.children)
|
||||||
|
if count == 0:
|
||||||
|
self.scroll.do_scroll_x = False
|
||||||
|
self.scroll.do_scroll_y = False
|
||||||
|
return
|
||||||
|
|
||||||
|
rows = math.ceil(count / COLS)
|
||||||
|
content_h = rows * BTN_H + (rows - 1) * SP + 2 * PAD
|
||||||
|
self.scroll.do_scroll_y = content_h > self.scroll.height
|
||||||
|
|
||||||
|
def _create_ucet_button(self, u: data.UcetSelect):
|
||||||
|
ui_type = ucet_ui_type(u)
|
||||||
|
color = UCET_COLORS.get(ui_type, (0.3, 0.3, 0.3, 1))
|
||||||
|
txt = self._format_closed_ucet(u) or ""
|
||||||
|
if not txt.strip():
|
||||||
|
txt = f"ID {getattr(u, 'id', '')}"
|
||||||
|
btn = Button(
|
||||||
|
text=txt,
|
||||||
|
size_hint=(None, None),
|
||||||
|
background_color=color,
|
||||||
|
width=BTN_W,
|
||||||
|
height=dp(130), # lehce vyšší pro 4–5 řádků
|
||||||
|
font_size=dp(12), # trochu menší
|
||||||
|
halign="center",
|
||||||
|
valign="top", )
|
||||||
|
btn.bind(
|
||||||
|
size=lambda b, *_: setattr(
|
||||||
|
b, "text_size", (b.width - dp(10), None)
|
||||||
|
))
|
||||||
|
ucislo = getattr(u, "ucislo", None)
|
||||||
|
if ucislo is None:
|
||||||
|
btn.disabled = True
|
||||||
|
btn.opacity = 0.4
|
||||||
|
return btn
|
||||||
|
btn.ucislo = ucislo
|
||||||
|
btn.bind(on_press=lambda b: self._select(b.ucislo))
|
||||||
|
return btn
|
||||||
|
|
||||||
|
def _format_closed_ucet(self, u):
|
||||||
|
lines = []
|
||||||
|
# --- měna (fallback) potreba najit alesponmenu s s kurzem 1!!!
|
||||||
|
unit = (
|
||||||
|
getattr(u, "unit", None)
|
||||||
|
or getattr(u, "mena", None)
|
||||||
|
or getattr(u, "currency", None)
|
||||||
|
or "Kč"
|
||||||
|
)
|
||||||
|
# 1) origin + stůl
|
||||||
|
txt = ""
|
||||||
|
if getattr(u, "origin", None):
|
||||||
|
txt += f"{u.origin}"
|
||||||
|
if getattr(u, "stul", None):
|
||||||
|
if txt:
|
||||||
|
txt += " "
|
||||||
|
txt += f"stůl {u.stul}"
|
||||||
|
if txt:
|
||||||
|
lines.append(txt)
|
||||||
|
# 2) číslo účtu + čas uzavření
|
||||||
|
txt = ""
|
||||||
|
if getattr(u, "ucislo", None):
|
||||||
|
txt += f"{u.ucislo}"
|
||||||
|
if getattr(u, "autor", None):
|
||||||
|
if txt:
|
||||||
|
txt += f" | by {u.autor}"
|
||||||
|
if txt:
|
||||||
|
lines.append(txt)
|
||||||
|
txt = ""
|
||||||
|
if getattr(u, "closed_at", None): #zatim nech
|
||||||
|
if txt:
|
||||||
|
txt += " | "
|
||||||
|
txt += f"{u.closed_at}"
|
||||||
|
if txt:
|
||||||
|
lines.append(txt)
|
||||||
|
# 3) suma
|
||||||
|
if getattr(u,"total_base_currency", None):
|
||||||
|
lines.append(f"{u.total_base_currency:,.2f} {unit}")
|
||||||
|
if getattr(u, "is_storno", None):
|
||||||
|
lines.append(f"Puvodni ucet {u.is_storno}")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def _matches_filter(self, u: data.UcetSelect, query: str) -> bool:
|
||||||
|
if not query:
|
||||||
|
return True
|
||||||
|
fields = [
|
||||||
|
getattr(u, "ucislo", ""),
|
||||||
|
getattr(u, "stul", ""),
|
||||||
|
getattr(u, "closed_at", ""),
|
||||||
|
getattr(u, "autor", ""),
|
||||||
|
getattr(u, "origin", ""),
|
||||||
|
f"{getattr(u, 'total_base_currency', 0) or 0:.2f}",
|
||||||
|
]
|
||||||
|
text = " ".join(str(v or "") for v in fields).lower()
|
||||||
|
return query.lower() in text
|
||||||
|
|
||||||
|
def _on_search_text(self, *_):
|
||||||
|
self._render_ucty()
|
||||||
|
|
||||||
|
def _render_ucty(self):
|
||||||
|
if not getattr(self, "grid", None):
|
||||||
|
return
|
||||||
|
self.grid.clear_widgets()
|
||||||
|
query = (self.search_input.text or "").strip()
|
||||||
|
ucty = [u for u in self._all_ucty if self._matches_filter(u, query)]
|
||||||
|
# seřadit podle čísla účtu vzestupně
|
||||||
|
ucty_sorted = sorted(
|
||||||
|
ucty,
|
||||||
|
key=lambda u: u.ucislo or "", reverse=True )
|
||||||
|
for u in ucty_sorted:
|
||||||
|
btn = self._create_ucet_button(u)
|
||||||
|
if btn:
|
||||||
|
self.grid.add_widget(btn)
|
||||||
|
Clock.schedule_once(self._update_scroll, 0)
|
||||||
|
|
||||||
|
def _load_ucty(self, ucty: list[data.UcetSelect]):
|
||||||
|
self._all_ucty = list(ucty or [])
|
||||||
|
self._render_ucty()
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
ucty = self.get_ucty() or []
|
||||||
|
self._load_ucty(ucty)
|
||||||
|
|
||||||
|
|
||||||
|
def load_closed_ucty(self):
|
||||||
|
return [u for u in self.load_stoly() if u.closed]
|
||||||
|
|
||||||
@@ -0,0 +1,647 @@
|
|||||||
|
import calendar
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
from kivy.clock import Clock
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.checkbox import CheckBox
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.uix.popup import Popup
|
||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.core.window import Window
|
||||||
|
|
||||||
|
import data
|
||||||
|
from numberpad import NumberPad
|
||||||
|
|
||||||
|
|
||||||
|
class ClosedReceiptsScreen(Screen):
|
||||||
|
def __init__(self, *, controller, back_screen="account_select", **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.controller = controller
|
||||||
|
self.back_screen = back_screen
|
||||||
|
self.receipts: list[data.UcetSelect] = []
|
||||||
|
self.filtered: list[data.UcetSelect] = []
|
||||||
|
self.selected_summary: data.UcetSelect | None = None
|
||||||
|
self.selected_ucet: data.Ucet | None = None
|
||||||
|
self.selected_quantities: dict[str, float] = {}
|
||||||
|
self.current_only = True
|
||||||
|
self._keyboard_bound = False
|
||||||
|
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(6), padding=dp(8))
|
||||||
|
|
||||||
|
top = BoxLayout(size_hint_y=None, height=dp(48), spacing=dp(6))
|
||||||
|
btn_back = Button(text="Zavriet", size_hint_x=None, width=dp(120))
|
||||||
|
btn_back.bind(on_press=lambda *_: self._go_back())
|
||||||
|
self.search = TextInput(
|
||||||
|
hint_text="Hladat ucet, stol, platbu, casnika...",
|
||||||
|
multiline=False,
|
||||||
|
font_size=dp(16),
|
||||||
|
padding=(dp(10), dp(10), dp(10), dp(8)),
|
||||||
|
)
|
||||||
|
self.search.bind(text=lambda *_: self._apply_filters())
|
||||||
|
self.date_filter = TextInput(
|
||||||
|
hint_text="Den",
|
||||||
|
multiline=False,
|
||||||
|
size_hint_x=None,
|
||||||
|
width=dp(120),
|
||||||
|
readonly=True,
|
||||||
|
font_size=dp(16),
|
||||||
|
padding=(dp(10), dp(10), dp(10), dp(8)),
|
||||||
|
)
|
||||||
|
self.date_filter.bind(text=lambda *_: self._apply_filters())
|
||||||
|
btn_date = Button(text="...", size_hint_x=None, width=dp(48))
|
||||||
|
btn_date.bind(on_press=lambda *_: self._open_calendar())
|
||||||
|
btn_clear_date = Button(text="X", size_hint_x=None, width=dp(42))
|
||||||
|
btn_clear_date.bind(on_press=lambda *_: setattr(self.date_filter, "text", ""))
|
||||||
|
current_wrap = BoxLayout(size_hint_x=None, width=dp(170), spacing=dp(4))
|
||||||
|
self.chk_current = CheckBox(active=True, size_hint_x=None, width=dp(36))
|
||||||
|
self.chk_current.bind(active=lambda _w, active: self._set_current_only(active))
|
||||||
|
current_wrap.add_widget(self.chk_current)
|
||||||
|
current_wrap.add_widget(Label(text="Aktualne ucty", halign="left"))
|
||||||
|
btn_refresh = Button(text="Obnovit", size_hint_x=None, width=dp(120))
|
||||||
|
btn_refresh.bind(on_press=lambda *_: self.refresh())
|
||||||
|
top.add_widget(btn_back)
|
||||||
|
top.add_widget(self.search)
|
||||||
|
top.add_widget(self.date_filter)
|
||||||
|
top.add_widget(btn_date)
|
||||||
|
top.add_widget(btn_clear_date)
|
||||||
|
top.add_widget(current_wrap)
|
||||||
|
top.add_widget(btn_refresh)
|
||||||
|
root.add_widget(top)
|
||||||
|
|
||||||
|
body = BoxLayout(spacing=dp(8))
|
||||||
|
left = BoxLayout(orientation="vertical", size_hint_x=0.62, spacing=dp(4))
|
||||||
|
header = GridLayout(cols=7, size_hint_y=None, height=dp(34), spacing=dp(2))
|
||||||
|
for title in ("Stav", "Ucet", "Datum", "Stol", "Platby", "Suma", "Casnik"):
|
||||||
|
header.add_widget(Label(text=f"[b]{title}[/b]", markup=True, halign="left"))
|
||||||
|
left.add_widget(header)
|
||||||
|
self.list_grid = GridLayout(cols=1, spacing=dp(2), size_hint_y=None)
|
||||||
|
self.list_grid.bind(minimum_height=self.list_grid.setter("height"))
|
||||||
|
list_scroll = ScrollView(do_scroll_x=False, do_scroll_y=True, bar_width=dp(14))
|
||||||
|
list_scroll.add_widget(self.list_grid)
|
||||||
|
left.add_widget(list_scroll)
|
||||||
|
body.add_widget(left)
|
||||||
|
|
||||||
|
right = BoxLayout(orientation="vertical", size_hint_x=0.38, spacing=dp(6))
|
||||||
|
self.detail_title = Label(
|
||||||
|
text="Vyber ucet",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(36),
|
||||||
|
font_size=dp(20),
|
||||||
|
bold=True,
|
||||||
|
)
|
||||||
|
self.detail_subtitle = Label(text="", size_hint_y=None, height=dp(28))
|
||||||
|
right.add_widget(self.detail_title)
|
||||||
|
right.add_widget(self.detail_subtitle)
|
||||||
|
self.detail_grid = GridLayout(cols=1, spacing=dp(2), size_hint_y=None)
|
||||||
|
self.detail_grid.bind(minimum_height=self.detail_grid.setter("height"))
|
||||||
|
detail_scroll = ScrollView(do_scroll_x=False, do_scroll_y=True, bar_width=dp(14))
|
||||||
|
detail_scroll.add_widget(self.detail_grid)
|
||||||
|
right.add_widget(detail_scroll)
|
||||||
|
|
||||||
|
actions = GridLayout(cols=2, spacing=dp(6), size_hint_y=None, height=dp(148))
|
||||||
|
self.btn_storno = self._action_button("Stornovat ucet", self._storno)
|
||||||
|
self.btn_return_table = self._action_button("Storno a presun na stol", self._return_to_table)
|
||||||
|
self.btn_copy = self._action_button("Tlac kopie", self._print_copy)
|
||||||
|
self.btn_change_pay = self._action_button("Zmenit platby", self._change_payment)
|
||||||
|
self.btn_tip = self._action_button("Zadanie TIPu", self._edit_tip)
|
||||||
|
self.btn_select_all = self._action_button("Vybrat vsetko", self._select_all_items)
|
||||||
|
for btn in (
|
||||||
|
self.btn_storno,
|
||||||
|
self.btn_return_table,
|
||||||
|
self.btn_copy,
|
||||||
|
self.btn_change_pay,
|
||||||
|
self.btn_tip,
|
||||||
|
self.btn_select_all,
|
||||||
|
):
|
||||||
|
actions.add_widget(btn)
|
||||||
|
right.add_widget(actions)
|
||||||
|
body.add_widget(right)
|
||||||
|
|
||||||
|
root.add_widget(body)
|
||||||
|
self.add_widget(root)
|
||||||
|
self._refresh_actions()
|
||||||
|
|
||||||
|
def on_enter(self):
|
||||||
|
self._bind_keyboard()
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def on_leave(self):
|
||||||
|
self._unbind_keyboard()
|
||||||
|
|
||||||
|
def _bind_keyboard(self):
|
||||||
|
if self._keyboard_bound:
|
||||||
|
return
|
||||||
|
Window.unbind(on_key_down=self._on_key_down)
|
||||||
|
Window.bind(on_key_down=self._on_key_down)
|
||||||
|
self._keyboard_bound = True
|
||||||
|
|
||||||
|
def _unbind_keyboard(self):
|
||||||
|
Window.unbind(on_key_down=self._on_key_down)
|
||||||
|
self._keyboard_bound = False
|
||||||
|
|
||||||
|
def _normalize_key(self, keycode, text):
|
||||||
|
if text:
|
||||||
|
return text
|
||||||
|
if keycode == 27:
|
||||||
|
return "ESC"
|
||||||
|
key = keycode[1] if isinstance(keycode, tuple) else keycode
|
||||||
|
return {
|
||||||
|
"escape": "ESC",
|
||||||
|
"esc": "ESC",
|
||||||
|
}.get(key, key)
|
||||||
|
|
||||||
|
def _on_key_down(self, window, keycode, scancode, codepoint, modifiers):
|
||||||
|
key = self._normalize_key(keycode, codepoint)
|
||||||
|
if key == "ESC":
|
||||||
|
self._go_back()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _action_button(self, text, callback):
|
||||||
|
btn = Button(text=text)
|
||||||
|
btn.bind(on_press=lambda *_: callback())
|
||||||
|
return btn
|
||||||
|
|
||||||
|
def _set_current_only(self, active: bool):
|
||||||
|
self.current_only = bool(active)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def _go_back(self):
|
||||||
|
if self.manager:
|
||||||
|
self.manager.current = self.back_screen
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
try:
|
||||||
|
self.receipts = self.controller.load_closed_ucty(
|
||||||
|
limit=2000,
|
||||||
|
onlynonclsrep=self.current_only,
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
Logger.exception("ClosedReceipts: load failed")
|
||||||
|
self.controller._popup_info("Ucty", f"Ucty sa nepodarilo nacitat:\n{exc}")
|
||||||
|
self.receipts = []
|
||||||
|
self.selected_summary = None
|
||||||
|
self.selected_ucet = None
|
||||||
|
self.selected_quantities = {}
|
||||||
|
self._apply_filters()
|
||||||
|
self._render_detail()
|
||||||
|
|
||||||
|
def _apply_filters(self):
|
||||||
|
text = (self.search.text or "").strip().lower()
|
||||||
|
date_text = (self.date_filter.text or "").strip()
|
||||||
|
result = []
|
||||||
|
for row in self.receipts:
|
||||||
|
if not self.current_only and not getattr(row, "c_uzaverka", None):
|
||||||
|
continue
|
||||||
|
if self.current_only and getattr(row, "c_uzaverka", None):
|
||||||
|
continue
|
||||||
|
if date_text and self._date_key(getattr(row, "closed_at", "")) != self._normalize_date(date_text):
|
||||||
|
continue
|
||||||
|
if text and text not in self._summary_search_text(row):
|
||||||
|
continue
|
||||||
|
result.append(row)
|
||||||
|
self.filtered = result
|
||||||
|
self._render_list()
|
||||||
|
|
||||||
|
def _summary_search_text(self, row) -> str:
|
||||||
|
fields = [
|
||||||
|
getattr(row, "ucislo", ""),
|
||||||
|
getattr(row, "closed_at", ""),
|
||||||
|
getattr(row, "stul", ""),
|
||||||
|
getattr(row, "payments_text", ""),
|
||||||
|
getattr(row, "status_text", ""),
|
||||||
|
getattr(row, "autor", ""),
|
||||||
|
getattr(row, "origin", ""),
|
||||||
|
f"{getattr(row, 'total_base_currency', 0) or 0:.2f}",
|
||||||
|
]
|
||||||
|
return " ".join(str(x or "") for x in fields).lower()
|
||||||
|
|
||||||
|
def _normalize_date(self, value: str) -> str:
|
||||||
|
value = (value or "").strip()
|
||||||
|
if not value:
|
||||||
|
return ""
|
||||||
|
for fmt in ("%d.%m.%Y", "%d.%m.%y", "%Y-%m-%d", "%y%m%d"):
|
||||||
|
try:
|
||||||
|
return datetime.strptime(value, fmt).strftime("%Y-%m-%d")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _date_key(self, value: str) -> str:
|
||||||
|
text = str(value or "").strip()
|
||||||
|
if not text:
|
||||||
|
return ""
|
||||||
|
candidates = [
|
||||||
|
text,
|
||||||
|
text[:19],
|
||||||
|
text[:16],
|
||||||
|
text[:15],
|
||||||
|
text[:13],
|
||||||
|
text[:10],
|
||||||
|
text[:8],
|
||||||
|
text[:6],
|
||||||
|
]
|
||||||
|
formats = (
|
||||||
|
"%y%m%d %H:%M:%S",
|
||||||
|
"%y%m%d %H:%M",
|
||||||
|
"%Y-%m-%d %H:%M:%S",
|
||||||
|
"%Y-%m-%d %H:%M",
|
||||||
|
"%d.%m.%Y %H:%M:%S",
|
||||||
|
"%d.%m.%Y %H:%M",
|
||||||
|
"%Y-%m-%d",
|
||||||
|
"%d.%m.%Y",
|
||||||
|
"%y%m%d",
|
||||||
|
)
|
||||||
|
for candidate in candidates:
|
||||||
|
for fmt in formats:
|
||||||
|
try:
|
||||||
|
return datetime.strptime(candidate, fmt).strftime("%Y-%m-%d")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if len(text) >= 6 and text[:6].isdigit():
|
||||||
|
try:
|
||||||
|
return datetime.strptime(text[:6], "%y%m%d").strftime("%Y-%m-%d")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return text[:10]
|
||||||
|
|
||||||
|
def _open_calendar(self):
|
||||||
|
selected = self._parse_date_filter() or date.today()
|
||||||
|
month = date(selected.year, selected.month, 1)
|
||||||
|
popup = Popup(title="Vyber datumu", size_hint=(None, None), size=(dp(430), dp(430)))
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(6), padding=dp(8))
|
||||||
|
|
||||||
|
def render(target_month):
|
||||||
|
root.clear_widgets()
|
||||||
|
top = BoxLayout(size_hint_y=None, height=dp(46), spacing=dp(6))
|
||||||
|
btn_prev = Button(text="<", size_hint_x=None, width=dp(54))
|
||||||
|
title = Label(text=target_month.strftime("%m/%Y"), bold=True)
|
||||||
|
btn_next = Button(text=">", size_hint_x=None, width=dp(54))
|
||||||
|
top.add_widget(btn_prev)
|
||||||
|
top.add_widget(title)
|
||||||
|
top.add_widget(btn_next)
|
||||||
|
root.add_widget(top)
|
||||||
|
|
||||||
|
days = GridLayout(cols=7, spacing=dp(3), size_hint_y=None, height=dp(34))
|
||||||
|
for name in ("Po", "Ut", "St", "Stv", "Pi", "So", "Ne"):
|
||||||
|
days.add_widget(Label(text=name, bold=True))
|
||||||
|
root.add_widget(days)
|
||||||
|
|
||||||
|
grid = GridLayout(cols=7, spacing=dp(3))
|
||||||
|
cal = calendar.Calendar(firstweekday=0)
|
||||||
|
for week in cal.monthdayscalendar(target_month.year, target_month.month):
|
||||||
|
for day in week:
|
||||||
|
if not day:
|
||||||
|
grid.add_widget(Label(text=""))
|
||||||
|
continue
|
||||||
|
current = date(target_month.year, target_month.month, day)
|
||||||
|
btn = Button(text=str(day))
|
||||||
|
if current == selected:
|
||||||
|
btn.background_color = (0.20, 0.55, 0.75, 1)
|
||||||
|
btn.bind(on_press=lambda _btn, d=current: self._set_calendar_date(popup, d))
|
||||||
|
grid.add_widget(btn)
|
||||||
|
root.add_widget(grid)
|
||||||
|
|
||||||
|
bottom = BoxLayout(size_hint_y=None, height=dp(46), spacing=dp(6))
|
||||||
|
btn_today = Button(text="Dnes")
|
||||||
|
btn_clear = Button(text="Bez datumu")
|
||||||
|
btn_cancel = Button(text="Zrusit")
|
||||||
|
btn_today.bind(on_press=lambda *_: self._set_calendar_date(popup, date.today()))
|
||||||
|
btn_clear.bind(on_press=lambda *_: self._clear_calendar_date(popup))
|
||||||
|
btn_cancel.bind(on_press=lambda *_: popup.dismiss())
|
||||||
|
bottom.add_widget(btn_today)
|
||||||
|
bottom.add_widget(btn_clear)
|
||||||
|
bottom.add_widget(btn_cancel)
|
||||||
|
root.add_widget(bottom)
|
||||||
|
|
||||||
|
prev_month = date(target_month.year - (1 if target_month.month == 1 else 0), 12 if target_month.month == 1 else target_month.month - 1, 1)
|
||||||
|
next_month = date(target_month.year + (1 if target_month.month == 12 else 0), 1 if target_month.month == 12 else target_month.month + 1, 1)
|
||||||
|
btn_prev.bind(on_press=lambda *_: render(prev_month))
|
||||||
|
btn_next.bind(on_press=lambda *_: render(next_month))
|
||||||
|
|
||||||
|
popup.content = root
|
||||||
|
render(month)
|
||||||
|
popup.open()
|
||||||
|
|
||||||
|
def _parse_date_filter(self):
|
||||||
|
text = (self.date_filter.text or "").strip()
|
||||||
|
if not text:
|
||||||
|
return None
|
||||||
|
key = self._normalize_date(text)
|
||||||
|
try:
|
||||||
|
return datetime.strptime(key, "%Y-%m-%d").date()
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _set_calendar_date(self, popup, value: date):
|
||||||
|
self.date_filter.text = value.strftime("%d.%m.%Y")
|
||||||
|
popup.dismiss()
|
||||||
|
|
||||||
|
def _clear_calendar_date(self, popup):
|
||||||
|
self.date_filter.text = ""
|
||||||
|
popup.dismiss()
|
||||||
|
|
||||||
|
def _render_list(self):
|
||||||
|
self.list_grid.clear_widgets()
|
||||||
|
for row in self.filtered:
|
||||||
|
btn = Button(
|
||||||
|
text=self._row_text(row),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(54),
|
||||||
|
halign="left",
|
||||||
|
valign="middle",
|
||||||
|
)
|
||||||
|
btn.text_size = (dp(1100), None)
|
||||||
|
if self.selected_summary and getattr(row, "ucislo", "") == getattr(self.selected_summary, "ucislo", ""):
|
||||||
|
btn.background_color = (0.20, 0.55, 0.75, 1)
|
||||||
|
else:
|
||||||
|
status = str(getattr(row, "status_text", "") or "").upper()
|
||||||
|
if status == "STORNO":
|
||||||
|
btn.background_color = (0.52, 0.18, 0.18, 1)
|
||||||
|
elif status == "STORNOVANY":
|
||||||
|
btn.background_color = (0.36, 0.20, 0.20, 1)
|
||||||
|
elif status in ("CIAST. STORNO", "VYSTORNOVANY"):
|
||||||
|
btn.background_color = (0.55, 0.42, 0.18, 1)
|
||||||
|
btn.bind(on_press=lambda _btn, item=row: self._select_receipt(item))
|
||||||
|
self.list_grid.add_widget(btn)
|
||||||
|
|
||||||
|
def _row_text(self, row) -> str:
|
||||||
|
return (
|
||||||
|
f"{getattr(row, 'status_text', '') or 'UCET'} "
|
||||||
|
f"# {getattr(row, 'ucislo', '')} "
|
||||||
|
f"{getattr(row, 'closed_at', '')} "
|
||||||
|
f"stol {getattr(row, 'stul', '') or '-'} "
|
||||||
|
f"{getattr(row, 'payments_text', '') or '-'} "
|
||||||
|
f"{self._money(getattr(row, 'total_base_currency', 0))} "
|
||||||
|
f"{getattr(row, 'autor', '') or '-'}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _money(self, value) -> str:
|
||||||
|
return f"{float(value or 0):.2f} {self.controller._currency()}"
|
||||||
|
|
||||||
|
def _select_receipt(self, row):
|
||||||
|
self.selected_summary = row
|
||||||
|
self.selected_quantities = {}
|
||||||
|
try:
|
||||||
|
self.selected_ucet = self.controller.load_closed_ucet_detail(row.ucislo)
|
||||||
|
except Exception as exc:
|
||||||
|
Logger.exception("ClosedReceipts: detail failed")
|
||||||
|
self.controller._popup_info("Ucty", f"Ucet {row.ucislo} sa nepodarilo nacitat:\n{exc}")
|
||||||
|
self.selected_ucet = None
|
||||||
|
self._render_list()
|
||||||
|
self._render_detail()
|
||||||
|
|
||||||
|
def _render_detail(self):
|
||||||
|
self.detail_grid.clear_widgets()
|
||||||
|
ucet = self.selected_ucet
|
||||||
|
if not ucet:
|
||||||
|
self.detail_title.text = "Vyber ucet"
|
||||||
|
self.detail_subtitle.text = ""
|
||||||
|
self._refresh_actions()
|
||||||
|
return
|
||||||
|
self.detail_title.text = f"Ucet {ucet.ucislo or ''}"
|
||||||
|
self.detail_subtitle.text = f"Stol {ucet.stul or '-'} | {ucet.closed_at or ''} | {self._money(ucet.total_czk())}"
|
||||||
|
for pol in getattr(ucet, "poloz", []) or []:
|
||||||
|
self.detail_grid.add_widget(self._item_row(pol))
|
||||||
|
self._refresh_actions()
|
||||||
|
|
||||||
|
def _item_row(self, pol):
|
||||||
|
line_id = self._line_id(pol)
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
selected = self.selected_quantities.get(line_id, 0.0)
|
||||||
|
partial = self._is_partially_storned(pol)
|
||||||
|
row = BoxLayout(
|
||||||
|
orientation="horizontal",
|
||||||
|
spacing=dp(4),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(78),
|
||||||
|
)
|
||||||
|
bg = (0.30, 0.30, 0.30, 1)
|
||||||
|
if available <= 0:
|
||||||
|
bg = (0.35, 0.35, 0.35, 1)
|
||||||
|
elif partial:
|
||||||
|
bg = (0.55, 0.42, 0.18, 1)
|
||||||
|
elif selected:
|
||||||
|
bg = (0.20, 0.55, 0.75, 1)
|
||||||
|
qty_btn = Button(
|
||||||
|
text=self._left_qty_text(pol),
|
||||||
|
markup=True,
|
||||||
|
size_hint=(None, None),
|
||||||
|
width=dp(74),
|
||||||
|
height=dp(78),
|
||||||
|
background_color=bg,
|
||||||
|
background_normal="",
|
||||||
|
background_down="",
|
||||||
|
halign="center",
|
||||||
|
valign="top",
|
||||||
|
disabled=available <= 0,
|
||||||
|
)
|
||||||
|
qty_btn.bind(on_press=lambda *_: self._select_quantity_with_numberpad(pol))
|
||||||
|
qty_btn.bind(size=lambda inst, *_: setattr(inst, "text_size", inst.size))
|
||||||
|
name_btn = Button(
|
||||||
|
text=self._item_text(pol),
|
||||||
|
markup=True,
|
||||||
|
size_hint=(1, None),
|
||||||
|
height=dp(78),
|
||||||
|
background_color=bg,
|
||||||
|
background_normal="",
|
||||||
|
background_down="",
|
||||||
|
halign="left",
|
||||||
|
valign="top",
|
||||||
|
disabled=available <= 0,
|
||||||
|
)
|
||||||
|
name_btn.bind(on_press=lambda *_: self._toggle_all_units(pol))
|
||||||
|
name_btn.bind(size=lambda inst, *_: setattr(inst, "text_size", (inst.width - dp(8), None)))
|
||||||
|
row.add_widget(qty_btn)
|
||||||
|
row.add_widget(name_btn)
|
||||||
|
return row
|
||||||
|
|
||||||
|
def _item_text(self, pol) -> str:
|
||||||
|
units = abs(float(getattr(pol, "pocet", 0) or 0))
|
||||||
|
qty = units / max(int(getattr(pol, "delitel", 1) or 1), 1)
|
||||||
|
total = qty * float(getattr(pol, "cena", 0) or 0)
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
return (
|
||||||
|
f"{getattr(pol, 'nazev', '')}\n"
|
||||||
|
f"Pocet: {qty:g} Stornovat: {self._qty_text(available, pol)} "
|
||||||
|
f"{float(getattr(pol, 'cena', 0) or 0):.2f} = {total:.2f}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _line_id(self, pol) -> str:
|
||||||
|
return str(getattr(pol, "line_id", "") or "")
|
||||||
|
|
||||||
|
def _storno_available_units(self, pol) -> float:
|
||||||
|
units = abs(float(getattr(pol, "pocet", 0) or 0))
|
||||||
|
raw = getattr(pol, "kstornu", None)
|
||||||
|
if raw is None:
|
||||||
|
return units
|
||||||
|
try:
|
||||||
|
return max(min(float(raw or 0), units), 0.0)
|
||||||
|
except Exception:
|
||||||
|
return units
|
||||||
|
|
||||||
|
def _qty_text(self, units, pol) -> str:
|
||||||
|
units = float(units or 0)
|
||||||
|
den = max(int(getattr(pol, "delitel", 1) or 1), 1)
|
||||||
|
if den != 1:
|
||||||
|
num = int(units) if float(units).is_integer() else units
|
||||||
|
return f"{num:g}/{den}"
|
||||||
|
return f"{int(units) if float(units).is_integer() else units:g}"
|
||||||
|
|
||||||
|
def _left_qty_text(self, pol) -> str:
|
||||||
|
line_id = self._line_id(pol)
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
selected = self.selected_quantities.get(line_id, 0.0)
|
||||||
|
available_txt = self._qty_text(available, pol)
|
||||||
|
if selected and selected < available:
|
||||||
|
return f"{self._qty_text(selected, pol)}\n/{available_txt}"
|
||||||
|
return available_txt
|
||||||
|
|
||||||
|
def _select_quantity_with_numberpad(self, pol):
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
if available <= 0:
|
||||||
|
return
|
||||||
|
current = self.selected_quantities.get(self._line_id(pol), 0.0)
|
||||||
|
initial = str(int(current or available))
|
||||||
|
|
||||||
|
def accept(value: str):
|
||||||
|
try:
|
||||||
|
qty = int(str(value or "0").strip())
|
||||||
|
except Exception:
|
||||||
|
return
|
||||||
|
self._set_selected_units(pol, min(max(qty, 0), available))
|
||||||
|
|
||||||
|
NumberPad(
|
||||||
|
mode="number",
|
||||||
|
allow_fraction=False,
|
||||||
|
show_dot=False,
|
||||||
|
decimal_places=0,
|
||||||
|
max_len=4,
|
||||||
|
initial_value=initial,
|
||||||
|
on_accept=accept,
|
||||||
|
).open()
|
||||||
|
|
||||||
|
def _toggle_all_units(self, pol):
|
||||||
|
line_id = self._line_id(pol)
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
if not line_id or available <= 0:
|
||||||
|
return
|
||||||
|
selected = self.selected_quantities.get(line_id, 0.0)
|
||||||
|
if selected >= available:
|
||||||
|
self._set_selected_units(pol, 0)
|
||||||
|
else:
|
||||||
|
self._set_selected_units(pol, available)
|
||||||
|
|
||||||
|
def _is_partially_storned(self, pol) -> bool:
|
||||||
|
raw = getattr(pol, "kstornu", None)
|
||||||
|
if raw is None:
|
||||||
|
return False
|
||||||
|
units = abs(float(getattr(pol, "pocet", 0) or 0))
|
||||||
|
try:
|
||||||
|
available = float(raw or 0)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return 0 <= available < units
|
||||||
|
|
||||||
|
def _change_selected_units(self, pol, delta: int):
|
||||||
|
line_id = self._line_id(pol)
|
||||||
|
if not line_id:
|
||||||
|
return
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
current = self.selected_quantities.get(line_id, 0.0)
|
||||||
|
self._set_selected_units(pol, current + float(delta))
|
||||||
|
|
||||||
|
def _set_selected_units(self, pol, value):
|
||||||
|
line_id = self._line_id(pol)
|
||||||
|
if not line_id:
|
||||||
|
return
|
||||||
|
available = self._storno_available_units(pol)
|
||||||
|
value = max(min(float(value or 0), available), 0.0)
|
||||||
|
if value <= 0:
|
||||||
|
self.selected_quantities.pop(line_id, None)
|
||||||
|
else:
|
||||||
|
self.selected_quantities[line_id] = value
|
||||||
|
Clock.schedule_once(lambda *_: self._render_detail(), 0)
|
||||||
|
|
||||||
|
def _select_all_items(self):
|
||||||
|
ucet = self.selected_ucet
|
||||||
|
if not ucet:
|
||||||
|
return
|
||||||
|
all_quantities = {
|
||||||
|
self._line_id(pol): self._storno_available_units(pol)
|
||||||
|
for pol in (getattr(ucet, "poloz", []) or [])
|
||||||
|
if self._line_id(pol) and self._storno_available_units(pol) > 0
|
||||||
|
}
|
||||||
|
if self.selected_quantities == all_quantities:
|
||||||
|
self.selected_quantities = {}
|
||||||
|
else:
|
||||||
|
self.selected_quantities = all_quantities
|
||||||
|
self._render_detail()
|
||||||
|
|
||||||
|
def _refresh_actions(self):
|
||||||
|
has_ucet = bool(self.selected_ucet)
|
||||||
|
has_selected = bool(self.selected_quantities)
|
||||||
|
is_storno = bool(getattr(self.selected_ucet, "is_storno", None)) if self.selected_ucet else False
|
||||||
|
is_limit = bool(getattr(self.selected_ucet, "limit_id", None)) if self.selected_ucet else False
|
||||||
|
has_storno_available = self._has_storno_available()
|
||||||
|
self.btn_storno.text = "Storno vybraneho" if has_selected else "Stornovat ucet"
|
||||||
|
for btn in (self.btn_storno, self.btn_return_table, self.btn_copy, self.btn_change_pay, self.btn_tip, self.btn_select_all):
|
||||||
|
btn.disabled = not has_ucet
|
||||||
|
if has_ucet and is_storno:
|
||||||
|
self.btn_storno.disabled = True
|
||||||
|
self.btn_return_table.disabled = True
|
||||||
|
self.btn_change_pay.disabled = True
|
||||||
|
self.btn_tip.disabled = True
|
||||||
|
if has_ucet and is_limit:
|
||||||
|
self.btn_return_table.disabled = True
|
||||||
|
self.btn_select_all.disabled = True
|
||||||
|
if has_selected:
|
||||||
|
self.btn_storno.disabled = True
|
||||||
|
self.btn_storno.text = "Stornovat ucet"
|
||||||
|
if has_ucet and not has_storno_available:
|
||||||
|
self.btn_storno.disabled = True
|
||||||
|
self.btn_select_all.disabled = True
|
||||||
|
|
||||||
|
def _has_storno_available(self) -> bool:
|
||||||
|
ucet = self.selected_ucet
|
||||||
|
if not ucet:
|
||||||
|
return False
|
||||||
|
return any(
|
||||||
|
self._storno_available_units(pol) > 0
|
||||||
|
for pol in (getattr(ucet, "poloz", []) or [])
|
||||||
|
)
|
||||||
|
|
||||||
|
def _print_copy(self):
|
||||||
|
if self.selected_ucet:
|
||||||
|
self.controller.closed_receipt_print_copy(self.selected_ucet)
|
||||||
|
|
||||||
|
def _storno(self):
|
||||||
|
if self.selected_ucet:
|
||||||
|
if getattr(self.selected_ucet, "limit_id", None):
|
||||||
|
self.selected_quantities = {}
|
||||||
|
self.controller.closed_receipt_storno_full(self.selected_ucet)
|
||||||
|
return
|
||||||
|
if self.selected_quantities:
|
||||||
|
self.controller.closed_receipt_storno_items(self.selected_ucet, self.selected_quantities)
|
||||||
|
self.selected_quantities = {}
|
||||||
|
self.refresh()
|
||||||
|
else:
|
||||||
|
self.controller.closed_receipt_storno_full(self.selected_ucet)
|
||||||
|
|
||||||
|
def _return_to_table(self):
|
||||||
|
if self.selected_ucet:
|
||||||
|
self.controller.closed_receipt_storno_return_to_table(self.selected_ucet)
|
||||||
|
|
||||||
|
def _change_payment(self):
|
||||||
|
if self.selected_ucet:
|
||||||
|
self.controller.closed_receipt_change_payment(self.selected_ucet)
|
||||||
|
|
||||||
|
def _edit_tip(self):
|
||||||
|
if self.selected_ucet:
|
||||||
|
self.controller.closed_receipt_edit_tip(self.selected_ucet)
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
from data import (
|
||||||
|
ClosureInterval,
|
||||||
|
ClosureSummary,
|
||||||
|
ClosureUser,
|
||||||
|
ClosureVAT,
|
||||||
|
ClosureReportOut,
|
||||||
|
)
|
||||||
|
def compute_closure_report(conn,
|
||||||
|
table_ucty: str,
|
||||||
|
table_clsrep: str | None=None,
|
||||||
|
ucislo_st: str | None=None,
|
||||||
|
ucislo_end: str | None=None,
|
||||||
|
id_kas: str="") -> ClosureReportOut | None:
|
||||||
|
|
||||||
|
if not table_clsrep:
|
||||||
|
table_clsrep = table_ucty.replace("_ucty", "_clsrep")
|
||||||
|
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# 1️⃣ URČENÍ STARTU
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
if not ucislo_st:
|
||||||
|
|
||||||
|
# zjisti poslední uzávěrku
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT ucislo_end
|
||||||
|
FROM "{table_clsrep}"
|
||||||
|
WHERE id_kas=?
|
||||||
|
ORDER BY clsrep_id DESC
|
||||||
|
LIMIT 1
|
||||||
|
""", (id_kas,))
|
||||||
|
row = cur.fetchone()
|
||||||
|
|
||||||
|
if row and row[0]:
|
||||||
|
# další účet po poslední uzávěrce
|
||||||
|
ucislo_st = row[0]
|
||||||
|
else:
|
||||||
|
# žádná uzávěrka → vezmi první existující účet
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT MIN(ucislo)
|
||||||
|
FROM "{table_ucty}"
|
||||||
|
WHERE id_kas=?
|
||||||
|
AND closed_at IS NOT NULL
|
||||||
|
AND TRIM(ucislo) != ''
|
||||||
|
""", (id_kas,))
|
||||||
|
row = cur.fetchone()
|
||||||
|
ucislo_st = row[0] if row else None
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# 2️⃣ URČENÍ KONCE
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
if not ucislo_end:
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT MAX(ucislo)
|
||||||
|
FROM "{table_ucty}"
|
||||||
|
WHERE id_kas=?
|
||||||
|
AND closed_at IS NOT NULL
|
||||||
|
AND TRIM(ucislo) != ''
|
||||||
|
""", (id_kas,))
|
||||||
|
row = cur.fetchone()
|
||||||
|
ucislo_end = row[0] if row else None
|
||||||
|
|
||||||
|
if not ucislo_st or not ucislo_end:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# 3️⃣ NAČTENÍ ÚČTŮ
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT ucislo, closed_at, data
|
||||||
|
FROM "{table_ucty}"
|
||||||
|
WHERE id_kas=?
|
||||||
|
AND closed_at IS NOT NULL
|
||||||
|
AND TRIM(ucislo) != ''
|
||||||
|
AND ucislo>=?
|
||||||
|
AND ucislo<=?
|
||||||
|
ORDER BY ucislo
|
||||||
|
""", (id_kas, ucislo_st, ucislo_end))
|
||||||
|
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# --- interval ---
|
||||||
|
ucislo_first, closed_first, _ = rows[0]
|
||||||
|
ucislo_last, closed_last, _ = rows[-1]
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# 4️⃣ AGREGACE (stejná jako předtím)
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
by_payment = defaultdict(float)
|
||||||
|
by_user_total = defaultdict(float)
|
||||||
|
by_user_cash = defaultdict(float)
|
||||||
|
by_vat = defaultdict(lambda: {"zaklad": 0.0, "dan": 0.0})
|
||||||
|
|
||||||
|
total_base = 0.0
|
||||||
|
total_payments = 0.0
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for ucislo, closed_at, data_json in rows:
|
||||||
|
|
||||||
|
if not data_json:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
u = json.loads(data_json)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not u.get("ucislo"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
autor = u.get("autor") or "UNKNOWN"
|
||||||
|
|
||||||
|
base_val = u.get("total_base_currency") or 0.0
|
||||||
|
total_base += base_val
|
||||||
|
by_user_total[autor] += base_val
|
||||||
|
|
||||||
|
for p in u.get("platby", []) or []:
|
||||||
|
code = p.get("code") or "UNKNOWN"
|
||||||
|
suma = p.get("suma_czk") or 0.0
|
||||||
|
|
||||||
|
by_payment[code] += suma
|
||||||
|
total_payments += suma
|
||||||
|
|
||||||
|
if code == "CASH":
|
||||||
|
by_user_cash[autor] += suma
|
||||||
|
|
||||||
|
for d in u.get("dane", []) or []:
|
||||||
|
rate = str(d.get("rate"))
|
||||||
|
zaklad = d.get("zaklad") or 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = float(rate)
|
||||||
|
dan = zaklad * (r - 1)
|
||||||
|
except Exception:
|
||||||
|
dan = 0.0
|
||||||
|
|
||||||
|
by_vat[rate]["zaklad"] += zaklad
|
||||||
|
by_vat[rate]["dan"] += dan
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# 5️⃣ SLOŽENÍ MODELU
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
interval = ClosureInterval(
|
||||||
|
ucislo_od=ucislo_first,
|
||||||
|
ucislo_do=ucislo_last,
|
||||||
|
closed_at_od=closed_first,
|
||||||
|
closed_at_do=closed_last,
|
||||||
|
)
|
||||||
|
|
||||||
|
summary = ClosureSummary(
|
||||||
|
pocet_uctu=count,
|
||||||
|
total_base_currency=round(total_base, 2),
|
||||||
|
total_payments=round(total_payments, 2),
|
||||||
|
difference=round(total_base - total_payments, 2),
|
||||||
|
)
|
||||||
|
|
||||||
|
users = {
|
||||||
|
user: ClosureUser(
|
||||||
|
total_base_currency=round(by_user_total[user], 2),
|
||||||
|
hotovost=round(by_user_cash[user], 2),
|
||||||
|
)
|
||||||
|
for user in by_user_total
|
||||||
|
}
|
||||||
|
|
||||||
|
vat = {
|
||||||
|
rate: ClosureVAT(
|
||||||
|
zaklad=round(v["zaklad"], 2),
|
||||||
|
dan=round(v["dan"], 2),
|
||||||
|
celkem=round(v["zaklad"] + v["dan"], 2),
|
||||||
|
)
|
||||||
|
for rate, v in by_vat.items()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClosureReportOut(
|
||||||
|
blocked_by="",
|
||||||
|
clsrep_no=None,
|
||||||
|
created_at=None,
|
||||||
|
interval=interval,
|
||||||
|
summary=summary,
|
||||||
|
platby={k: round(v, 2) for k, v in by_payment.items()},
|
||||||
|
uzivatele=users,
|
||||||
|
dph=vat,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
import sqlite3
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
import kivy_printer
|
||||||
|
|
||||||
|
|
||||||
|
class TestApp(App):
|
||||||
|
def build(self):
|
||||||
|
|
||||||
|
with sqlite3.connect("testVIII.db") as conn:
|
||||||
|
rep = compute_closure_report(
|
||||||
|
conn,
|
||||||
|
table_ucty="00001_ucty",
|
||||||
|
#table_clsrep="00001_clsrep",
|
||||||
|
#ucislo_st="01000435",
|
||||||
|
#ucislo_end="01000500",
|
||||||
|
id_kas="01"
|
||||||
|
)
|
||||||
|
|
||||||
|
if rep:
|
||||||
|
print(rep.model_dump_json(indent=4, ensure_ascii=False))
|
||||||
|
kivy_printer.show_clsrep_preview(rep.model_dump())
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Uzávěrka je prázdná.")
|
||||||
|
|
||||||
|
return BoxLayout() # dummy root
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
TestApp().run()
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.uix.modalview import ModalView
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
|
||||||
|
class ClosureSelectDialog(ModalView):
|
||||||
|
def __init__(self, closures, on_select, title="Vyber uzávěrku", **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.size_hint = (None, None)
|
||||||
|
self.size = (dp(700), dp(700))
|
||||||
|
self.auto_dismiss = True
|
||||||
|
self.closures = closures or []
|
||||||
|
self.on_select = on_select
|
||||||
|
scroll = ScrollView(size_hint=(1, 1))
|
||||||
|
content = GridLayout(
|
||||||
|
cols=1,
|
||||||
|
spacing=dp(10),
|
||||||
|
padding=dp(12),
|
||||||
|
size_hint_y=None,
|
||||||
|
)
|
||||||
|
content.bind(minimum_height=content.setter("height"))
|
||||||
|
lbl_title = Label(
|
||||||
|
text=title,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(40),
|
||||||
|
)
|
||||||
|
content.add_widget(lbl_title)
|
||||||
|
for c in self.closures:
|
||||||
|
txt = self._closure_text(c)
|
||||||
|
btn = Button(
|
||||||
|
text=txt,
|
||||||
|
markup=True,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(90),
|
||||||
|
halign="left",
|
||||||
|
valign="middle",
|
||||||
|
text_size=(dp(650), None),
|
||||||
|
)
|
||||||
|
btn.bind(
|
||||||
|
size=lambda inst, val: setattr(
|
||||||
|
inst, "text_size", (inst.width - dp(20), None)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
btn.bind(
|
||||||
|
on_release=lambda inst, clsrep_no=c.clsrep_no: self._select(clsrep_no)
|
||||||
|
)
|
||||||
|
content.add_widget(btn)
|
||||||
|
btn_close = Button(
|
||||||
|
text="Zavřít",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(56),
|
||||||
|
)
|
||||||
|
btn_close.bind(on_release=self.dismiss)
|
||||||
|
content.add_widget(btn_close)
|
||||||
|
scroll.add_widget(content)
|
||||||
|
self.add_widget(scroll)
|
||||||
|
|
||||||
|
def _select(self, clsrep_no):
|
||||||
|
self.dismiss()
|
||||||
|
if self.on_select:
|
||||||
|
self.on_select(clsrep_no)
|
||||||
|
|
||||||
|
def _closure_text(self, c):
|
||||||
|
clsrep_no = getattr(c, "clsrep_no", "") or ""
|
||||||
|
ucislo_od = getattr(c, "ucislo_od", "") or ""
|
||||||
|
ucislo_do = getattr(c, "ucislo_do", "") or ""
|
||||||
|
closed_at_od = getattr(c, "closed_at_od", "") or ""
|
||||||
|
closed_at_do = getattr(c, "closed_at_do", "") or ""
|
||||||
|
|
||||||
|
return (
|
||||||
|
f"[b]Uzávěrka {clsrep_no}[/b]\n"
|
||||||
|
f"Účty: {ucislo_od} - {ucislo_do}\n"
|
||||||
|
f"Od: {closed_at_od}\n"
|
||||||
|
f"Do: {closed_at_do}"
|
||||||
|
)
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://127.0.0.1:8000",
|
||||||
|
"refresh_url": "http://127.0.0.1:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "07",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://127.0.0.1:8000",
|
||||||
|
"refresh_url": "http://127.0.0.1:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://192.168.0.145:8000",
|
||||||
|
"refresh_url": "http://192.168.0.145:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://192.168.180.133:8000",
|
||||||
|
"refresh_url": "http://192.168.180.133:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://192.168.180.133:8081",
|
||||||
|
"refresh_url": "http://192.168.180.133:8081/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
+1686
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from decimal import Decimal, ROUND_HALF_UP
|
||||||
|
|
||||||
|
import data
|
||||||
|
import postgres_service
|
||||||
|
|
||||||
|
|
||||||
|
class FidelioDbError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _s(value) -> str:
|
||||||
|
return "" if value is None else str(value).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _i(value, default: int = 0) -> int:
|
||||||
|
try:
|
||||||
|
return int(float(str(value).strip().strip("\"'")))
|
||||||
|
except Exception:
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def _money(value) -> Decimal:
|
||||||
|
try:
|
||||||
|
return Decimal(str(value).replace(",", ".")).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||||
|
except Exception:
|
||||||
|
return Decimal("0.00")
|
||||||
|
|
||||||
|
|
||||||
|
def _quote_ident(name: str) -> str:
|
||||||
|
name = _s(name)
|
||||||
|
if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", name):
|
||||||
|
raise FidelioDbError(f"Neplatny PostgreSQL identifikator: {name}")
|
||||||
|
return f'"{name}"'
|
||||||
|
|
||||||
|
|
||||||
|
def _table(conn: data.PostgresConnection, table_name: str) -> str:
|
||||||
|
schema = _s(getattr(conn, "schema_", "")) or "food600"
|
||||||
|
return f"{_quote_ident(schema)}.{_quote_ident(table_name)}"
|
||||||
|
|
||||||
|
|
||||||
|
def _now_parts():
|
||||||
|
now = datetime.now()
|
||||||
|
return now, now.strftime("%y%m%d"), now.strftime("%H%M%S")
|
||||||
|
|
||||||
|
|
||||||
|
def _db_out_defaults() -> dict:
|
||||||
|
now, dat, cas = _now_parts()
|
||||||
|
payload = {
|
||||||
|
"typ": "",
|
||||||
|
"stav": "I",
|
||||||
|
"cis_kasy": "",
|
||||||
|
"outlet": "",
|
||||||
|
"porad_tiz": "",
|
||||||
|
"pokoj": "",
|
||||||
|
"datum": now.date(),
|
||||||
|
"sekund": Decimal("0.000"),
|
||||||
|
"dat": dat,
|
||||||
|
"cas": cas,
|
||||||
|
"ucet_kasa": "",
|
||||||
|
"serv_per": "",
|
||||||
|
"folio": "",
|
||||||
|
"gn": "",
|
||||||
|
"p_hostu": "",
|
||||||
|
"total": Decimal("0.00"),
|
||||||
|
"dysko": Decimal("0.00"),
|
||||||
|
"pm": "",
|
||||||
|
"ckar": "",
|
||||||
|
"track2": "",
|
||||||
|
"retrans": Decimal("0"),
|
||||||
|
}
|
||||||
|
for idx in range(1, 10):
|
||||||
|
payload[f"s{idx}"] = Decimal("0.00")
|
||||||
|
payload[f"d{idx}"] = Decimal("0.00")
|
||||||
|
payload[f"t{idx}"] = Decimal("0.00")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def _insert_db_out(pg, conn: data.PostgresConnection, payload: dict) -> int:
|
||||||
|
table = _table(conn, "db_out")
|
||||||
|
columns = [
|
||||||
|
"typ", "stav", "cis_kasy", "outlet", "porad_tiz", "pokoj",
|
||||||
|
"datum", "sekund", "dat", "cas", "ucet_kasa", "serv_per",
|
||||||
|
"folio", "gn", "p_hostu", "total",
|
||||||
|
"s1", "d1", "t1", "s2", "d2", "t2", "s3", "d3", "t3",
|
||||||
|
"s4", "d4", "t4", "s5", "d5", "t5", "s6", "d6", "t6",
|
||||||
|
"s7", "d7", "t7", "s8", "d8", "t8", "s9", "d9", "t9",
|
||||||
|
"dysko", "pm", "ckar", "track2", "retrans",
|
||||||
|
]
|
||||||
|
placeholders = ", ".join(["%s"] * len(columns))
|
||||||
|
column_sql = ", ".join(_quote_ident(col) for col in columns)
|
||||||
|
values = [payload.get(col) for col in columns]
|
||||||
|
cur = pg.cursor()
|
||||||
|
try:
|
||||||
|
cur.execute(
|
||||||
|
f"INSERT INTO {table} ({column_sql}) VALUES ({placeholders}) RETURNING postseqnr",
|
||||||
|
values,
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
pg.commit()
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
return int(row[0])
|
||||||
|
|
||||||
|
|
||||||
|
def _mark_request_done(pg, conn: data.PostgresConnection, postseqnr: int, db_in_id: int | None = None) -> None:
|
||||||
|
cur = pg.cursor()
|
||||||
|
try:
|
||||||
|
cur.execute(
|
||||||
|
f"UPDATE {_table(conn, 'db_out')} SET stav=%s WHERE postseqnr=%s",
|
||||||
|
("O", postseqnr),
|
||||||
|
)
|
||||||
|
if db_in_id is not None:
|
||||||
|
cur.execute(
|
||||||
|
f"UPDATE {_table(conn, 'db_in')} SET stav=%s WHERE idriadok=%s",
|
||||||
|
("O", db_in_id),
|
||||||
|
)
|
||||||
|
pg.commit()
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_answer(pg, conn: data.PostgresConnection, postseqnr: int, timeout_seconds: int = 30) -> dict | None:
|
||||||
|
table = _table(conn, "db_in")
|
||||||
|
columns = [
|
||||||
|
"idriadok", "odpoved", "kecy", "pokoj1",
|
||||||
|
"folio1", "gn1", "pokoj2", "folio2", "gn2",
|
||||||
|
"pokoj3", "folio3", "gn3", "pokoj4", "folio4", "gn4",
|
||||||
|
]
|
||||||
|
column_sql = ", ".join(_quote_ident(col) for col in columns)
|
||||||
|
deadline = time.time() + max(1, int(timeout_seconds or 30))
|
||||||
|
while time.time() < deadline:
|
||||||
|
cur = pg.cursor()
|
||||||
|
try:
|
||||||
|
cur.execute(
|
||||||
|
f"SELECT {column_sql} FROM {table} WHERE postseqnr=%s ORDER BY idriadok LIMIT 1",
|
||||||
|
(postseqnr,),
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
if row:
|
||||||
|
return dict(zip(columns, row))
|
||||||
|
time.sleep(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _is_ok_answer(answer: dict) -> bool:
|
||||||
|
value = _s(answer.get("odpoved")).upper()
|
||||||
|
return value in {"", "OK", "UR"}
|
||||||
|
|
||||||
|
|
||||||
|
def _guest_from_answer(answer: dict, idx: int) -> data.HotelGuest | None:
|
||||||
|
folio = _s(answer.get(f"folio{idx}"))
|
||||||
|
if not folio:
|
||||||
|
return None
|
||||||
|
room_code = _s(answer.get(f"pokoj{idx}")) or _s(answer.get("pokoj1"))
|
||||||
|
return data.HotelGuest(
|
||||||
|
id=folio,
|
||||||
|
account_id=folio,
|
||||||
|
guest_name=_s(answer.get(f"gn{idx}")),
|
||||||
|
room_id=room_code,
|
||||||
|
room_code=room_code,
|
||||||
|
result=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_guests(
|
||||||
|
conn: data.PostgresConnection,
|
||||||
|
id_kas: str,
|
||||||
|
params: dict,
|
||||||
|
room_code: str = "",
|
||||||
|
track2: str = "",
|
||||||
|
timeout_seconds: int = 30,
|
||||||
|
) -> list[data.HotelGuest]:
|
||||||
|
width = _i((params or {}).get("fidelio_izba_znakov"), 3)
|
||||||
|
room_code = _s(room_code)
|
||||||
|
track2 = _s(track2)
|
||||||
|
if len(room_code) >= width:
|
||||||
|
width = len(room_code)
|
||||||
|
track2 = ""
|
||||||
|
elif not room_code:
|
||||||
|
width = 0
|
||||||
|
|
||||||
|
payload = _db_out_defaults()
|
||||||
|
payload.update({
|
||||||
|
"typ": "DOTAZ",
|
||||||
|
"cis_kasy": _s(id_kas),
|
||||||
|
"outlet": _s(id_kas),
|
||||||
|
"pokoj": room_code.rjust(width, "0"),
|
||||||
|
"track2": track2,
|
||||||
|
})
|
||||||
|
|
||||||
|
with postgres_service.connect(conn) as pg:
|
||||||
|
postseqnr = _insert_db_out(pg, conn, payload)
|
||||||
|
answer = _wait_for_answer(pg, conn, postseqnr, timeout_seconds=timeout_seconds)
|
||||||
|
if not answer:
|
||||||
|
_mark_request_done(pg, conn, postseqnr)
|
||||||
|
raise FidelioDbError("Opera neodpoveda.")
|
||||||
|
_mark_request_done(pg, conn, postseqnr, _i(answer.get("idriadok")))
|
||||||
|
|
||||||
|
if not _is_ok_answer(answer):
|
||||||
|
raise FidelioDbError(_s(answer.get("kecy")) or "Opera vratila chybu.")
|
||||||
|
|
||||||
|
guests = []
|
||||||
|
for idx in range(1, 5):
|
||||||
|
guest = _guest_from_answer(answer, idx)
|
||||||
|
if guest:
|
||||||
|
guests.append(guest)
|
||||||
|
return guests
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_mag_card(card_code: str) -> tuple[str, str]:
|
||||||
|
code = _s(card_code)
|
||||||
|
if code.startswith("%") and "?" in code:
|
||||||
|
code = code[1:code.find("?")]
|
||||||
|
elif code.startswith("5") and "<" in code:
|
||||||
|
code = code[1:code.find("<")]
|
||||||
|
elif code.startswith("_") and "<" in code:
|
||||||
|
code = code[1:code.find("<")]
|
||||||
|
else:
|
||||||
|
raise FidelioDbError("Neznamy format hotelovej karty.")
|
||||||
|
|
||||||
|
replacements = {
|
||||||
|
"+": "1",
|
||||||
|
"\u013e": "2",
|
||||||
|
"\u0161": "3",
|
||||||
|
"\u010d": "4",
|
||||||
|
"\u0165": "5",
|
||||||
|
"\u017e": "6",
|
||||||
|
"\u00fd": "7",
|
||||||
|
"\u00e1": "8",
|
||||||
|
"\u00ed": "9",
|
||||||
|
"\u00e9": "0",
|
||||||
|
"!": "1",
|
||||||
|
"@": "2",
|
||||||
|
"#": "3",
|
||||||
|
"$": "4",
|
||||||
|
"%": "5",
|
||||||
|
"^": "6",
|
||||||
|
"&": "7",
|
||||||
|
"*": "8",
|
||||||
|
"(": "9",
|
||||||
|
")": "0",
|
||||||
|
}
|
||||||
|
for src, dst in replacements.items():
|
||||||
|
code = code.replace(src, dst)
|
||||||
|
try:
|
||||||
|
room_code = str(int(code[30:34]))
|
||||||
|
except Exception as e:
|
||||||
|
raise FidelioDbError("Neznamy format hotelovej karty.") from e
|
||||||
|
try:
|
||||||
|
guest_id = str(int(code[10:20]))
|
||||||
|
except Exception:
|
||||||
|
guest_id = ""
|
||||||
|
try:
|
||||||
|
checkout = datetime.strptime(code[20:30], "%y%m%d%H%M")
|
||||||
|
except Exception as e:
|
||||||
|
raise FidelioDbError("Neznamy format hotelovej karty.") from e
|
||||||
|
if checkout < datetime.now():
|
||||||
|
raise FidelioDbError("Nacitana hotelova karta je neplatna.")
|
||||||
|
return room_code, guest_id
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_salto_card(card_code: str) -> str:
|
||||||
|
code = _s(card_code)
|
||||||
|
normalized = ""
|
||||||
|
while code:
|
||||||
|
if len(code) > 1:
|
||||||
|
normalized += code[-2:]
|
||||||
|
code = code[:-2]
|
||||||
|
else:
|
||||||
|
normalized += code
|
||||||
|
code = ""
|
||||||
|
return normalized.ljust(14, "0")
|
||||||
|
|
||||||
|
|
||||||
|
def check_card(
|
||||||
|
conn: data.PostgresConnection,
|
||||||
|
id_kas: str,
|
||||||
|
params: dict,
|
||||||
|
card_code: str,
|
||||||
|
timeout_seconds: int = 30,
|
||||||
|
) -> data.HotelCardResult:
|
||||||
|
params = params or {}
|
||||||
|
card_type = _s(params.get("hotel_karta_typ") or "SALTO").strip("\"'").upper()
|
||||||
|
length = _i(params.get("hotel_karta_length"), 14)
|
||||||
|
guest_id = ""
|
||||||
|
if card_type == "SALTO":
|
||||||
|
room_code = ""
|
||||||
|
track2 = _normalize_salto_card(card_code)
|
||||||
|
elif card_type == "MAG":
|
||||||
|
room_code, guest_id = _normalize_mag_card(card_code)
|
||||||
|
track2 = room_code
|
||||||
|
else:
|
||||||
|
room_code = ""
|
||||||
|
track2 = _s(card_code).ljust(length, "0") if length else _s(card_code)
|
||||||
|
|
||||||
|
guests = load_guests(
|
||||||
|
conn,
|
||||||
|
id_kas=id_kas,
|
||||||
|
params=params,
|
||||||
|
room_code=room_code,
|
||||||
|
track2=track2,
|
||||||
|
timeout_seconds=timeout_seconds,
|
||||||
|
)
|
||||||
|
if guest_id:
|
||||||
|
guests = [guest for guest in guests if _s(guest.id) == guest_id] or guests
|
||||||
|
if not guests:
|
||||||
|
raise FidelioDbError("Ku karte sa nenasiel ziadny host.")
|
||||||
|
guest = guests[0]
|
||||||
|
return data.HotelCardResult(
|
||||||
|
room_id=guest.room_id,
|
||||||
|
room_code=guest.room_code,
|
||||||
|
account_id=guest.account_id or guest.id,
|
||||||
|
guest_id=guest.id,
|
||||||
|
guest_name=guest.guest_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _raster_index(value) -> int:
|
||||||
|
idx = _i(value, 1)
|
||||||
|
if idx < 1 or idx > 9:
|
||||||
|
return 1
|
||||||
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
def _charge_amounts(preparation: data.HotelChargePreparation) -> list[Decimal]:
|
||||||
|
amounts = [Decimal("0.00") for _ in range(9)]
|
||||||
|
for line in preparation.lines or []:
|
||||||
|
idx = _raster_index(line.raster_id)
|
||||||
|
amounts[idx - 1] += _money(line.amount)
|
||||||
|
return [amount.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) for amount in amounts]
|
||||||
|
|
||||||
|
|
||||||
|
def charge_account(
|
||||||
|
conn: data.PostgresConnection,
|
||||||
|
id_kas: str,
|
||||||
|
preparation: data.HotelChargePreparation,
|
||||||
|
timeout_seconds: int = 30,
|
||||||
|
) -> dict:
|
||||||
|
if not preparation or not preparation.ready:
|
||||||
|
raise FidelioDbError("Hotelovy ucet nie je pripraveny na odoslanie.")
|
||||||
|
target = preparation.target
|
||||||
|
if not target:
|
||||||
|
raise FidelioDbError("Hotelovy ucet nema ciel.")
|
||||||
|
|
||||||
|
amounts = _charge_amounts(preparation)
|
||||||
|
total = sum(amounts, Decimal("0.00")).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||||
|
if not total:
|
||||||
|
raise FidelioDbError("Hotelovy ucet nema ziadnu sumu na odoslanie.")
|
||||||
|
|
||||||
|
payload = _db_out_defaults()
|
||||||
|
payload.update({
|
||||||
|
"typ": "ZATIZ",
|
||||||
|
"cis_kasy": _s(id_kas),
|
||||||
|
"outlet": _s(id_kas),
|
||||||
|
"pokoj": _s(target.room_code),
|
||||||
|
"serv_per": _s(target.time_attribute)[:1],
|
||||||
|
"gn": _s(target.guest_name),
|
||||||
|
"folio": _s(target.guest_id or target.account_id),
|
||||||
|
"ucet_kasa": _s(preparation.receipt_number)[-7:],
|
||||||
|
"total": total,
|
||||||
|
})
|
||||||
|
for idx, amount in enumerate(amounts, start=1):
|
||||||
|
payload[f"s{idx}"] = amount
|
||||||
|
|
||||||
|
with postgres_service.connect(conn) as pg:
|
||||||
|
postseqnr = _insert_db_out(pg, conn, payload)
|
||||||
|
logger.info(
|
||||||
|
"Fidelio ZATIZ inserted: postseqnr=%s id_kas=%s pokoj=%s folio=%s "
|
||||||
|
"ucet_kasa=%s total=%s amounts=%s",
|
||||||
|
postseqnr,
|
||||||
|
_s(id_kas),
|
||||||
|
payload["pokoj"],
|
||||||
|
payload["folio"],
|
||||||
|
payload["ucet_kasa"],
|
||||||
|
total,
|
||||||
|
[str(x) for x in amounts],
|
||||||
|
)
|
||||||
|
answer = _wait_for_answer(pg, conn, postseqnr, timeout_seconds=timeout_seconds)
|
||||||
|
if not answer:
|
||||||
|
_mark_request_done(pg, conn, postseqnr)
|
||||||
|
raise FidelioDbError("Opera neodpoveda.")
|
||||||
|
_mark_request_done(pg, conn, postseqnr, _i(answer.get("idriadok")))
|
||||||
|
|
||||||
|
if not _is_ok_answer(answer):
|
||||||
|
raise FidelioDbError(_s(answer.get("kecy")) or "Opera vratila chybu.")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"request_number": postseqnr,
|
||||||
|
"message": "OK",
|
||||||
|
}
|
||||||
+1120
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
|||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_LANG = "sk"
|
||||||
|
SUPPORTED_LANGS = {"sk", "cs", "en", "de", "hu", "pl", "it"}
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_lang(lang: str | None) -> str:
|
||||||
|
value = str(lang or DEFAULT_LANG).strip().lower()
|
||||||
|
if value == "cz":
|
||||||
|
value = "cs"
|
||||||
|
return value if value in SUPPORTED_LANGS else DEFAULT_LANG
|
||||||
|
|
||||||
|
|
||||||
|
class Translator:
|
||||||
|
def __init__(self, lang: str = DEFAULT_LANG, locale_dir: str | Path | None = None):
|
||||||
|
self.locale_dir = Path(locale_dir) if locale_dir else Path(__file__).with_name("locales")
|
||||||
|
self.lang = DEFAULT_LANG
|
||||||
|
self.messages: dict[str, str] = {}
|
||||||
|
self.set_lang(lang)
|
||||||
|
|
||||||
|
def set_lang(self, lang: str | None):
|
||||||
|
self.lang = normalize_lang(lang)
|
||||||
|
fallback = self._load(DEFAULT_LANG)
|
||||||
|
current = self._load(self.lang) if self.lang != DEFAULT_LANG else {}
|
||||||
|
self.messages = {**fallback, **current}
|
||||||
|
|
||||||
|
def _load(self, lang: str) -> dict[str, str]:
|
||||||
|
path = self.locale_dir / f"{normalize_lang(lang)}.json"
|
||||||
|
if not path.exists():
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
with path.open("r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Invalid locale JSON : {e}")
|
||||||
|
return {}
|
||||||
|
return {str(k): str(v) for k, v in data.items()}
|
||||||
|
|
||||||
|
def tr(self, key: str, default: str | None = None, **kwargs) -> str:
|
||||||
|
text = self.messages.get(key, default if default is not None else key)
|
||||||
|
if kwargs:
|
||||||
|
try:
|
||||||
|
return text.format(**kwargs)
|
||||||
|
except Exception:
|
||||||
|
return text
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def available_locales(locale_dir: str | Path | None = None) -> list[str]:
|
||||||
|
base = Path(locale_dir) if locale_dir else Path(__file__).with_name("locales")
|
||||||
|
if not base.exists():
|
||||||
|
return []
|
||||||
|
return sorted(path.stem for path in base.glob("*.json"))
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
|||||||
|
client
|
||||||
|
|
||||||
|
kivy grafika
|
||||||
|
pydantic kontrola typu (pro komunikaci server x client)
|
||||||
|
requests klientska kommunikace se serverem
|
||||||
|
qrcode generovani qr kodu pro placeni
|
||||||
|
pillow import a zobraceni obrazku (pro qr platbu)
|
||||||
|
|
||||||
|
|
||||||
|
server
|
||||||
|
uvicorn http server
|
||||||
|
fastapi --"--
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
client
|
||||||
|
|
||||||
|
kivy grafika
|
||||||
|
pydantic kontrola typu (pro komunikaci server x client)
|
||||||
|
requests klientska kommunikace se serverem
|
||||||
|
qrcode generovani qr kodu pro placeni
|
||||||
|
pillow import a zobraceni obrazku (pro qr platbu)
|
||||||
|
|
||||||
|
|
||||||
|
server
|
||||||
|
uvicorn http server
|
||||||
|
fastapi --"--
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
client
|
||||||
|
|
||||||
|
Python 3.11 nebo 3.12
|
||||||
|
po instalaci (napr. do c:\pokladna) v adresari pokladna vytvorit virtualni prostredi
|
||||||
|
pro w11 prikaz "py -m venv k3.12" nebo "python venv k3.12" (pred tim overit, pousti-li se opravdu python 3.11 resp.3.12)
|
||||||
|
potom z adresare pokladna "k3.12/script/activate" a prompt je pak
|
||||||
|
(k3.12) c:\pokladna
|
||||||
|
|
||||||
|
pak upgrade pip
|
||||||
|
pip install --upgrade pip setuptools wheel
|
||||||
|
a instalace kivy
|
||||||
|
pip install kivy[full]
|
||||||
|
a instalace zbytku
|
||||||
|
pip install pydantic, requests, qrcode, pillow
|
||||||
|
|
||||||
|
v config.json je nutne spravne vyplnit adresu a port serveru
|
||||||
|
|
||||||
|
a spusteni frontendu
|
||||||
|
|
||||||
|
python kivy_app.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kivy grafika
|
||||||
|
pydantic kontrola typu (pro komunikaci server x client)
|
||||||
|
requests klientska kommunikace se serverem
|
||||||
|
qrcode generovani qr kodu pro placeni
|
||||||
|
pillow import a zobraceni obrazku (pro qr platbu)
|
||||||
|
|
||||||
|
|
||||||
|
server
|
||||||
|
uvicorn http server
|
||||||
|
fastapi --"--
|
||||||
|
psycopg
|
||||||
|
jinja2
|
||||||
+965
@@ -0,0 +1,965 @@
|
|||||||
|
2026-06-10 14:58:59,847 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 14:58:59,883 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 14:58:59,884 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 14:58:59,884 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 14:58:59,888 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 14:58:59,930 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=6XDkFs4VibkMml9Z2f3tLfcg13X1tgQLVOuSTfg8icY
|
||||||
|
refresh_token=66Bmgd6dvixmm9259ePb251m4Tgsg1g448KLFkgVI5T2aAckXG4pUVY3TfWgoNJE
|
||||||
|
|
||||||
|
2026-06-10 14:59:00,038 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 14:59:00,073 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 14:59:00,080 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 14:59:00,080 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 14:59:00,081 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 14:59:00,082 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 14:59:00,089 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 14:59:00,089 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 14:59:00,101 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:01:34,671 [INFO] kivy: NumberPad CANCEL
|
||||||
|
2026-06-10 15:01:34,672 [INFO] kivy: LOGIN CANCEL
|
||||||
|
2026-06-10 15:01:34,672 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:01:34,673 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:01:34,673 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:01:36,716 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:01:36,717 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:01:39,706 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 15:01:39,736 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 15:01:39,737 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 15:01:39,737 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 15:01:39,740 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 15:01:39,791 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=gJTKANAzXxJHMlutmEQLCxzNtnAD7dgi8FO_svgSg04
|
||||||
|
refresh_token=lk5sFhC9poeHPKKlowtp2Kmo5bX5oA9C9sN0nh9acDPUBy2jF_oJm_lORbVKe5j5
|
||||||
|
|
||||||
|
2026-06-10 15:01:39,890 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:01:39,890 [WARNING] kivy: Hlavicky uctov sa podařilo načíst: userhead1=None userhead2=None userhead3=None userhead4=None userhead5=None userhead6=None userhead7=None userhead8=None userhead9=None usertail1=None usertail2=None usertail3=None usertail4=None usertail5=None usertail6=None
|
||||||
|
2026-06-10 15:01:39,937 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 15:01:39,959 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 15:01:39,959 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 15:01:39,959 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 15:01:39,959 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 15:01:39,964 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 15:01:39,964 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 15:01:39,976 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:03:00,081 [INFO] kivy: NumberPad CANCEL
|
||||||
|
2026-06-10 15:03:00,081 [INFO] kivy: LOGIN CANCEL
|
||||||
|
2026-06-10 15:03:00,081 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:03:00,081 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:03:00,082 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:03:00,189 [INFO] api_call: Heartbeat thread stopped
|
||||||
|
2026-06-10 15:03:00,233 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:03:00,235 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:03:02,982 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 15:03:03,021 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 15:03:03,022 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 15:03:03,023 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 15:03:03,026 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 15:03:03,069 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=Z_lM7fKhPyI84evXF3tBRWTja5ObDdluOqYXxshsSlU
|
||||||
|
refresh_token=6dkzH8dWE9I-o8YNLph_sFT_7I4lmlUeFsrSskVKEWdT8nuGq-xc-g3xEX9sR3lq
|
||||||
|
|
||||||
|
2026-06-10 15:03:03,170 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:03:03,171 [WARNING] kivy: Hlavicky uctov se nepodařilo načíst: unhashable type: 'dict'
|
||||||
|
2026-06-10 15:03:03,223 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 15:03:03,242 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 15:03:03,242 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 15:03:03,243 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 15:03:03,243 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 15:03:03,250 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 15:03:03,250 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 15:03:03,257 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:10:03,994 [INFO] kivy: NumberPad CANCEL
|
||||||
|
2026-06-10 15:10:03,995 [INFO] kivy: LOGIN CANCEL
|
||||||
|
2026-06-10 15:10:03,995 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:10:03,996 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:10:03,997 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:10:04,449 [INFO] api_call: Heartbeat thread stopped
|
||||||
|
2026-06-10 15:10:04,509 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:10:04,513 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:10:11,192 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 15:10:11,250 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 15:10:11,254 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 15:10:11,256 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 15:10:11,261 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 15:10:11,345 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=ZW0xvC_haO6kU64DE3YynWiouL0bEYaiNouvy12vlWE
|
||||||
|
refresh_token=C_EQMl7dHIHRQYEdlRlPkXn9IGnX6hSuWZH9p61z72n42fxMODBy8fDBMNyV-7UW
|
||||||
|
|
||||||
|
2026-06-10 15:10:11,464 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:10:11,466 [WARNING] kivy: Hlavicky uctov se nepodařilo načíst: 1 validation error for KasUtxtRiadky
|
||||||
|
JSON input should be string, bytes or bytearray [type=json_type, input_value={'userhead1': 'Norbert Fr...5': '', 'usertail6': ''}, input_type=dict]
|
||||||
|
For further information visit https://errors.pydantic.dev/2.12/v/json_type
|
||||||
|
2026-06-10 15:10:11,565 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 15:10:11,580 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 15:10:11,581 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 15:10:11,582 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 15:10:11,585 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 15:10:11,591 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 15:10:11,591 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 15:10:11,603 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:12:01,117 [INFO] kivy: NumberPad CANCEL
|
||||||
|
2026-06-10 15:12:01,118 [INFO] kivy: LOGIN CANCEL
|
||||||
|
2026-06-10 15:12:01,118 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:12:01,119 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:12:01,119 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:12:01,949 [INFO] api_call: Heartbeat thread stopped
|
||||||
|
2026-06-10 15:12:01,992 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:12:01,994 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:12:05,447 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 15:12:05,482 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 15:12:05,483 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 15:12:05,483 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 15:12:05,487 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 15:12:05,530 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=xkcpl6bMh8VJshIHNlvRp6d8iaGq2nZL0s-UV-cxLE4
|
||||||
|
refresh_token=AigsSsH6N5Z0VQ-kvbvB5fNCFtYhoL5Mg4Lc_Klw3m3tS8njqBlqG0xk8xXi03oM
|
||||||
|
|
||||||
|
2026-06-10 15:12:05,613 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:12:05,614 [WARNING] kivy: Hlavicky uctov sa podařilo načíst: {'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:12:05,649 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 15:12:05,657 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 15:12:05,657 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 15:12:05,658 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 15:12:05,658 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 15:12:05,664 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 15:12:05,664 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 15:12:05,677 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:12:55,666 [INFO] kivy: NumberPad CANCEL
|
||||||
|
2026-06-10 15:12:55,666 [INFO] kivy: LOGIN CANCEL
|
||||||
|
2026-06-10 15:12:55,666 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:12:55,666 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:12:55,667 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:12:55,789 [INFO] api_call: Heartbeat thread stopped
|
||||||
|
2026-06-10 15:12:55,826 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:12:55,827 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:13:01,179 [INFO] kivy: Inicializace ApiController
|
||||||
|
2026-06-10 15:13:01,224 [INFO] kivy: APP on_start → startuji backend init
|
||||||
|
2026-06-10 15:13:01,228 [INFO] kivy: Base: Start application main loop
|
||||||
|
2026-06-10 15:13:01,232 [INFO] kivy: GL: NPOT texture support is available
|
||||||
|
2026-06-10 15:13:01,237 [INFO] kivy: THREAD: start_app běží
|
||||||
|
2026-06-10 15:13:01,307 [INFO] api_call:
|
||||||
|
Přihlášení úspěšné
|
||||||
|
token=0tg_3Y64J-vHBSOYRR5YnMGjbuXwHmkoWtmdb5dxqEo
|
||||||
|
refresh_token=fw1R31O9TvxTNguBXb2uIMWC07IgarKGVknowhNdn5O485s4AMz02VRRitlEktgP
|
||||||
|
|
||||||
|
2026-06-10 15:13:01,416 [INFO] api_call: GET load_kasutxt_api: resp={'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:13:01,417 [WARNING] kivy: Hlavicky uctov sa podařilo načíst: {'userhead1': 'Norbert Frank - EUROINF TATRY', 'userhead2': 'Popradská 34', 'userhead3': '064 01 Stará Ľubovňa', 'userhead4': 'Salaš u Franka', 'userhead5': 'Popradská 34', 'userhead6': '064 01 Stará Ľubovňa', 'userhead7': '', 'userhead8': '', 'userhead9': '', 'usertail1': '', 'usertail2': '', 'usertail3': '', 'usertail4': '', 'usertail5': '', 'usertail6': ''}
|
||||||
|
2026-06-10 15:13:01,528 [INFO] kivy: CTRL: POS static maps built items=95, codes=96, search=64
|
||||||
|
2026-06-10 15:13:01,550 [INFO] api_call: Heartbeat thread started
|
||||||
|
2026-06-10 15:13:01,551 [INFO] kivy: Verze API 069_9_Kivy.API.hotel-target, verze frontend 069_8_Kivy.MB.hotel-restore
|
||||||
|
2026-06-10 15:13:01,552 [INFO] kivy: Aplikace připravena
|
||||||
|
2026-06-10 15:13:01,553 [INFO] kivy: THREAD RESULT = True
|
||||||
|
2026-06-10 15:13:01,564 [INFO] kivy: UI refresh po startu
|
||||||
|
2026-06-10 15:13:01,564 [INFO] kivy: UI ready → čekám na login
|
||||||
|
2026-06-10 15:13:01,576 [INFO] kivy: APP: show login user
|
||||||
|
2026-06-10 15:13:04,753 [INFO] kivy: NumberPad ACCEPT: 613190
|
||||||
|
2026-06-10 15:13:04,754 [INFO] kivy: CTRL: login_user
|
||||||
|
2026-06-10 15:13:04,788 [INFO] kivy: CTRL: user logged in: SYSTEM, permits=['PLATBA', 'PL_HOTOVE', 'SPLIT', 'PL_SELECT', 'DISCOUNT', 'STORNO_UCT', 'PL_CHG', 'CENHLAD', 'STORNO_PL', 'CLOSE']
|
||||||
|
2026-06-10 15:13:04,788 [INFO] kivy: LOGIN USER OK
|
||||||
|
2026-06-10 15:13:04,789 [INFO] kivy: APP: show_account_select
|
||||||
|
2026-06-10 15:13:05,195 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:13:05,196 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:13:05,223 [INFO] kivy: AccountSelect: start auto refresh
|
||||||
|
2026-06-10 15:13:06,225 [INFO] kivy: ACCOUNT SELECT → stul=6 mode=normal view=open_table
|
||||||
|
2026-06-10 15:13:06,226 [INFO] kivy: Opening table 6
|
||||||
|
2026-06-10 15:13:06,227 [INFO] kivy: CTRL: load_ucet stul=6
|
||||||
|
2026-06-10 15:13:06,260 [INFO] kivy: CTRL: open_posdialog
|
||||||
|
2026-06-10 15:13:06,342 [INFO] kivy: POS: set_ucet stul=6
|
||||||
|
2026-06-10 15:13:40,713 [INFO] kivy: CTRL: _on_pos_finish operation=edit_only
|
||||||
|
2026-06-10 15:13:40,715 [INFO] kivy: CTRL: POS finalize operation=edit_only
|
||||||
|
2026-06-10 15:13:40,715 [INFO] kivy: CTRL: edit_only
|
||||||
|
2026-06-10 15:13:41,259 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:13:41,260 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:13:41,292 [INFO] kivy: AccountSelect: start auto refresh
|
||||||
|
2026-06-10 15:13:46,258 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:13:46,259 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:13:46,259 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:13:51,263 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:13:51,263 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:13:51,265 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:13:56,260 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:13:56,261 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:13:56,261 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:01,256 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:01,256 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:01,257 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:06,258 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:06,258 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:06,259 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:11,260 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:11,262 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:11,264 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:16,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:16,264 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:16,265 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:21,268 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:21,270 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:21,271 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:26,271 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:26,271 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:26,272 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:31,272 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:31,272 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:31,273 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:36,273 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:36,275 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:36,277 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:41,268 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:41,268 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:41,269 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:46,265 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:46,265 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:46,266 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:51,261 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:51,261 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:51,262 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:14:56,266 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:14:56,267 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:14:56,267 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:01,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:01,265 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:01,265 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:06,263 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:06,264 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:06,264 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:11,266 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:11,266 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:11,267 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:16,265 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:16,266 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:16,267 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:21,260 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:21,260 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:21,261 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:26,267 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:26,267 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:26,268 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:31,263 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:31,263 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:31,264 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:36,267 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:36,268 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:36,268 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:41,263 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:41,265 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:41,266 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:46,267 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:46,268 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:46,268 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:51,268 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:51,269 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:51,269 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:15:56,268 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:15:56,269 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:15:56,270 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:01,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:01,265 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:01,267 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:06,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:06,266 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:06,267 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:11,270 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:11,270 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:11,271 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:16,275 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:16,276 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:16,276 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:21,270 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:21,274 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:21,276 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:26,292 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:26,293 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:26,294 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:31,287 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:31,288 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:31,288 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:36,292 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:36,294 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:36,295 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:41,287 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:41,287 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:41,288 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:46,288 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:46,289 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:46,289 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:51,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:51,285 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:51,287 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:16:56,286 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:16:56,287 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:16:56,288 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:01,292 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:01,294 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:01,295 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:06,292 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:06,293 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:06,294 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:11,291 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:11,293 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:11,294 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:16,288 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:16,289 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:16,289 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:21,291 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:21,292 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:21,294 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:26,286 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:26,287 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:26,288 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:31,280 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:31,281 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:31,282 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:36,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:36,286 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:36,288 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:41,280 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:41,280 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:41,281 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:46,274 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:46,276 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:46,277 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:51,271 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:51,273 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:51,275 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:17:56,269 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:17:56,269 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:17:56,270 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:01,263 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:01,264 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:01,265 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:06,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:06,266 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:06,268 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:11,264 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:11,264 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:11,265 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:16,267 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:16,268 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:16,270 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:21,274 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:21,274 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:21,275 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:26,273 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:26,273 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:26,274 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:31,277 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:31,278 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:31,279 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:36,282 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:36,284 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:36,286 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:41,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:41,285 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:41,286 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:46,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:46,284 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:46,286 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:51,281 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:51,283 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:51,284 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:18:56,282 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:18:56,283 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:18:56,283 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:01,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:01,284 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:01,285 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:06,279 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:06,280 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:06,280 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:11,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:11,284 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:11,286 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:16,282 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:16,283 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:16,283 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:21,288 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:21,289 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:21,291 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:26,283 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:26,283 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:26,284 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:31,280 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:31,280 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:31,281 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:36,281 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:36,282 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:36,283 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:41,276 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:41,277 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:41,278 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:46,274 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:46,276 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:46,277 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:51,274 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:51,274 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:51,275 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:19:56,275 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:19:56,276 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:19:56,278 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:01,273 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:01,274 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:01,274 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:06,277 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:06,277 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:06,278 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:11,278 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:11,278 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:11,279 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:16,282 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:16,284 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:16,285 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:21,279 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:21,279 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:21,280 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:26,275 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:26,276 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:26,276 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:31,281 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:31,281 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:31,282 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:36,281 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:36,281 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:36,282 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:41,287 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:41,288 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:41,289 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:46,291 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:46,293 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:46,294 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:51,295 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:51,296 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:51,297 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:20:56,301 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:20:56,301 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:20:56,302 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:01,306 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:01,306 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:01,307 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:06,321 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:06,322 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:06,323 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:11,321 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:11,321 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:11,322 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:16,318 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:16,318 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:16,319 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:21,321 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:21,322 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:21,323 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:26,326 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:26,326 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:26,327 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:31,324 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:31,324 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:31,325 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:36,326 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:36,328 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:36,329 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:41,328 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:41,330 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:41,331 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:46,331 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:46,331 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:46,332 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:51,327 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:51,330 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:51,331 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:21:56,324 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:21:56,324 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:21:56,325 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:01,320 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:01,320 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:01,321 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:06,326 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:06,326 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:06,327 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:11,325 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:11,325 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:11,326 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:16,327 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:16,327 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:16,328 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:21,331 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:21,332 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:21,332 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:26,335 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:26,337 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:26,338 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:31,333 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:31,333 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:31,334 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:36,339 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:36,339 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:36,339 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:41,338 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:41,338 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:41,339 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:46,342 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:46,342 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:46,343 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:51,346 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:51,346 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:51,347 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:22:56,346 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:22:56,346 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:22:56,347 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:01,353 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:01,357 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:01,358 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:06,358 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:06,360 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:06,361 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:11,361 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:11,364 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:11,365 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:16,359 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:16,360 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:16,361 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:21,366 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:21,367 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:21,367 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:26,370 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:26,371 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:26,373 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:31,371 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:31,392 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:31,392 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:36,373 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:36,374 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:36,374 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:41,369 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:41,369 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:41,370 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:46,374 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:46,376 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:46,377 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:51,374 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:51,375 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:51,375 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:23:56,372 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:23:56,373 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:23:56,374 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:01,376 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:01,378 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:01,379 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:06,381 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:06,382 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:06,382 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:11,379 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:11,381 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:11,382 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:16,383 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:16,383 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:16,384 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:21,386 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:21,386 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:21,387 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:26,386 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:26,386 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:26,387 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:31,391 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:31,391 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:31,392 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:36,389 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:36,389 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:36,390 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:41,392 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:41,394 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:41,395 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:46,390 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:46,391 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:46,392 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:51,402 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:51,402 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:51,403 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:24:56,404 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:24:56,404 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:24:56,405 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:01,410 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:01,412 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:01,414 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:06,414 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:06,417 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:06,418 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:11,418 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:11,419 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:11,419 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:16,416 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:16,417 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:16,417 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:21,422 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:21,422 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:21,423 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:26,426 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:26,427 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:26,428 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:31,422 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:31,423 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:31,423 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:36,427 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:36,428 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:36,430 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:41,439 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:41,440 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:41,441 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:46,438 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:46,438 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:46,439 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:51,442 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:51,443 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:51,445 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:25:56,441 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:25:56,442 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:25:56,444 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:01,445 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:01,447 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:01,449 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:06,447 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:06,448 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:06,448 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:11,442 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:11,445 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:11,447 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:16,469 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:16,470 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:16,471 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:21,474 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:21,476 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:21,478 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:26,471 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:26,474 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:26,476 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:31,474 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:31,474 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:31,475 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:36,479 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:36,480 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:36,481 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:41,482 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:41,483 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:41,483 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:46,483 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:46,485 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:46,486 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:51,477 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:51,477 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:51,478 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:26:56,479 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:26:56,481 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:26:56,483 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:01,476 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:01,476 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:01,477 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:06,482 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:06,482 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:06,483 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:11,479 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:11,479 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:11,480 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:16,474 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:16,474 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:16,475 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:21,474 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:21,475 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:21,476 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:26,477 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:26,477 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:26,477 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:31,472 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:31,473 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:31,474 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:36,475 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:36,476 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:36,476 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:41,472 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:41,472 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:41,473 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:46,468 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:46,468 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:46,469 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:51,471 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:51,471 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:51,472 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:27:56,477 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:27:56,478 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:27:56,478 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:01,475 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:01,477 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:01,478 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:04,498 [INFO] api_call: 401 → refreshing access token
|
||||||
|
2026-06-10 15:28:06,475 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:06,476 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:06,477 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:11,473 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:11,473 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:11,474 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:16,474 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:16,477 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:16,480 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:21,470 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:21,470 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:21,471 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:26,465 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:26,465 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:26,466 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:31,472 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:31,472 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:31,473 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:36,477 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:36,480 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:36,482 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:41,476 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:41,477 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:41,477 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:46,471 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:46,471 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:46,472 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:51,469 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:51,469 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:51,470 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:28:56,467 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:28:56,468 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:28:56,468 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:01,462 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:01,463 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:01,463 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:06,457 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:06,458 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:06,459 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:11,456 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:11,459 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:11,461 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:16,452 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:16,452 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:16,453 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:21,453 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:21,453 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:21,454 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:26,470 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:26,471 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:26,472 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:31,476 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:31,476 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:31,477 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:36,480 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:36,480 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:36,481 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:41,495 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:41,496 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:41,498 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:46,492 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:46,494 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:46,495 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:51,487 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:51,489 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:51,490 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:29:56,482 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:29:56,483 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:29:56,484 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:01,480 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:01,480 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:01,481 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:06,682 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:06,683 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:06,683 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:11,679 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:11,679 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:11,680 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:16,674 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:16,675 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:16,675 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:21,676 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:21,676 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:21,677 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:26,673 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:26,675 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:26,676 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:31,676 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:31,678 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:31,678 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:36,682 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:36,684 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:36,685 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:41,679 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:41,680 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:41,681 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:46,679 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:46,680 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:46,680 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:51,680 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:51,681 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:51,682 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:30:56,679 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:30:56,682 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:30:56,684 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:01,681 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:01,682 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:01,682 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:06,682 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:06,683 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:06,684 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:11,688 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:11,688 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:11,689 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:16,693 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:16,694 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:16,694 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:21,689 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:21,690 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:21,691 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:26,688 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:26,689 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:26,691 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:31,684 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:31,684 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:31,685 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:36,687 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:36,688 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:36,689 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:41,683 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:41,684 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:41,685 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:46,688 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:46,688 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:46,689 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:51,693 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:51,693 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:51,694 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:31:56,696 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:31:56,696 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:31:56,697 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:01,699 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:01,700 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:01,700 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:06,732 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:06,733 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:06,734 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:11,728 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:11,729 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:11,730 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:16,723 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:16,724 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:16,724 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:21,722 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:21,723 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:21,724 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:26,725 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:26,726 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:26,727 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:31,729 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:31,729 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:31,730 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:36,729 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:36,729 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:36,729 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:41,724 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:41,726 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:41,727 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:46,721 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:46,721 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:46,722 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:51,720 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:51,720 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:51,721 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:32:56,724 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:32:56,724 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:32:56,725 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:01,730 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:01,731 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:01,731 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:06,726 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:06,727 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:06,728 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:11,723 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:11,724 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:11,725 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:16,726 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:16,726 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:16,727 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:21,724 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:21,724 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:21,725 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:26,727 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:26,728 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:26,729 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:31,722 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:31,722 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:31,723 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:36,718 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:36,718 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:36,719 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:41,723 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:41,723 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:41,724 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:46,727 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:46,727 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:46,728 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:51,721 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:51,721 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:51,722 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:33:56,717 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:33:56,717 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:33:56,718 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:01,721 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:01,721 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:01,722 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:06,717 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:06,718 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:06,718 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:11,721 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:11,723 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:11,725 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:16,725 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:16,725 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:16,726 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:21,720 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:21,720 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:21,721 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:26,719 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:26,720 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:26,721 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:31,724 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:31,726 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:31,727 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:36,724 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:36,724 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:36,725 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:41,729 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:41,730 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:41,730 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:46,733 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:46,734 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:46,736 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:51,736 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:51,737 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:51,738 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:34:56,737 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:34:56,737 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:34:56,738 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:01,744 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:35:01,744 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:35:01,745 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:06,750 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:35:06,750 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:35:06,751 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:11,754 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:35:11,754 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:35:11,754 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:16,758 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:35:16,758 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:35:16,759 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:21,760 [WARNING] kivy: AccountSelect: TIMER TICK
|
||||||
|
2026-06-10 15:35:21,760 [WARNING] kivy: AccountSelect: REFRESH CALLED mode=open_table
|
||||||
|
2026-06-10 15:35:21,760 [INFO] kivy: CTRL: load_stoly
|
||||||
|
2026-06-10 15:35:21,885 [INFO] kivy: Kivy on_stop called
|
||||||
|
2026-06-10 15:35:21,886 [INFO] kivy: Application cleanup started
|
||||||
|
2026-06-10 15:35:21,887 [INFO] api_call: Stopping heartbeat
|
||||||
|
2026-06-10 15:35:23,926 [INFO] kivy: Base: Leaving application in progress...
|
||||||
|
2026-06-10 15:35:23,928 [INFO] kivy: Kivy on_stop called
|
||||||
+5629
File diff suppressed because it is too large
Load Diff
+1994
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
|||||||
|
Verze 1. Beta
|
||||||
|
|
||||||
|
spousteni primo pod pythonem
|
||||||
|
venv/Scripts/python.exe
|
||||||
|
|
||||||
|
|
||||||
|
ToDo:
|
||||||
|
-
|
||||||
|
-do blokovani na serveru dopln test na expiraci blocku
|
||||||
|
-blokovane stoly s jinou barvou a on_time aktivovat stav
|
||||||
|
-všude používat popup z kivu_app, je ještě posdialogu
|
||||||
|
-v souboru zkouska mas funkcni import configu, zarid to misto cteni parametru
|
||||||
|
-informacni blok (cislo pokladny, cisnik, defaultni hladina...)
|
||||||
|
-do ceniku stranky
|
||||||
|
-uzivatele
|
||||||
|
-opravneni, server je hotovy heslo 123 je zatím user AltoAdmin
|
||||||
|
-podivej se na tisky.py (je tam bordel)
|
||||||
|
-tisk bonu
|
||||||
|
pozor, při stornu odeslanych polozek mas v u_sec odeslane i ještě neodeslane
|
||||||
|
-vyzkousej TCP tisk
|
||||||
|
-vyhazej ze serveru endpointy pro users, které nejsou potřeba
|
||||||
|
-rozdelit server na endpointy a DB operace
|
||||||
|
-implementuj pojmenovane stul
|
||||||
|
-automaticky test
|
||||||
|
-vice pokladen, vice terminalu
|
||||||
|
-blokace, release
|
||||||
|
-relogin, refresh token
|
||||||
|
-start s novou databazi
|
||||||
|
-zkus jinou databazi (postgres nebo DuckDB)
|
||||||
|
-strukturovane setupy server i client, zvaz config.fp nacteni rovnou do objektu
|
||||||
|
|
||||||
|
Chyby:
|
||||||
|
|
||||||
|
Hotovo:
|
||||||
|
kivy_app, dodělat heartbeats
|
||||||
|
při stronu uctu jsou ve vyberu mezery, jako by tam byly ty odfiltrovane ucty
|
||||||
|
po celkove platbe pak nefunguje prohlizeni uctu
|
||||||
|
pokud stornujes ucet vznikly jako změna druhu platby, vznikne storno storna kladne
|
||||||
|
prohlizeni/kopie zaplaceneho uctu
|
||||||
|
pridana sleva
|
||||||
|
opraven vypocet DPH
|
||||||
|
storna odeslanych polozek jsou ted jen v otevrenem stole
|
||||||
|
zrusena storna odeslanych polozek z otevrenych uctu z accountselectdialog
|
||||||
|
změna druhu platby
|
||||||
|
storno uctu
|
||||||
|
do server endpointu volaného z load_stoly_API podle ucis pridan limit kolik posledních zaznamu (defaultne 50uctu, vraci close_at)
|
||||||
|
Když v zadani hesla das zrusit, pokladna se ma ukoncit
|
||||||
|
Server tvori databazi users a vlozi Alto admin
|
||||||
|
kdyz pri castecne platbe pouzijes Eura, zmizi puvodni ucet a nic se nezaplati
|
||||||
|
QR platba, IBAN a poznámku pro platce (pos_name) bere ze Setupu
|
||||||
|
setup uz nedela upgrade DB, moc to nefungovalo (zmeny nutno implementovat
|
||||||
|
jak do init_setup_tab tak do data)
|
||||||
|
logger pro clienta (misto printu if debug:)
|
||||||
|
heart beet
|
||||||
|
-automaticke odhlaseni mrtvol
|
||||||
|
-release bloku mrtvych klientu
|
||||||
|
-spousti se az po login
|
||||||
|
tisk uctu
|
||||||
|
Storno polozek z odeslanych uctu
|
||||||
|
Markovani kodem
|
||||||
|
Storno odeslanych polozek
|
||||||
|
Vytvorit spravne novou databazi s nulovym cislem uctu
|
||||||
|
Pouziva tokeny k autentifikaci, tokeny expiruji (kratky a dlouhy, oba ziskas pri prihlaseni)
|
||||||
|
callApi ma parametricky retry pri vypadku serveru
|
||||||
|
multi verze pro vic provozu a spolecnosti
|
||||||
|
do tokenu je pripojen na zacatek prefix na tabulky
|
||||||
|
existuje databaze spolecnosti s uzivateli, hesly a prefixy a tokeny
|
||||||
|
logovani, bud info nebo do souboru
|
||||||
|
heslo v databazi zakazek ulozeno kodovane
|
||||||
|
vic spolecnosti, tabulky zaklada automaticky
|
||||||
|
get_nucis fungovaje tak, ze když nenajde zadne číslo uctu, da xx000001,
|
||||||
|
jinak další v poradi xx00000, kde xx je cislo pokladny
|
||||||
|
cenik vytvoren, triden pro pokladny procedury save a load i delete je hotovy
|
||||||
|
login a autentifikace ted umi vice zakazniku a vice terminalu u jednoho zakaznika
|
||||||
|
id client je v hlavicce rq, je na nej vydan jeho token
|
||||||
|
tokeny a klienti v pohode, vse funguje i pro ruzne instance (terminaly)
|
||||||
|
polozky odeslany do kuchyne maji svuj atribut sent, maji jinou barvu a moznost omezit
|
||||||
|
akce na tlacitkach polozky uctu v ceniku zatim
|
||||||
|
pridany barvy butonu matice
|
||||||
|
hotovy setup, pro cislo pokladny (login, setup -> prace s POSDialog)
|
||||||
|
menu cenove hladiny vzdy nastaveny na aktualni, co se stane kdyz je Null
|
||||||
|
v ceniku i uctech je id_card, vybere se prvni hladina polozky ceniku
|
||||||
|
defaultni cenova hladina v setupu, lze menit v POSDialogu
|
||||||
|
hotovy dialog platby
|
||||||
|
mas block ucet a unblock ucet
|
||||||
|
get ucet defaultne ucet blokuje, uprest odblokuje
|
||||||
|
ucet ma metodu upsert (update/insert), cislo uctu prideli server pri platbe
|
||||||
|
na zaklade vyplneneho closed_at
|
||||||
|
get metoda ma param blokuj, upsert def odblokovava, ale ma moznost i ponechat zablokovany (pro pripad dlouho otevreneho uctu on timer update)
|
||||||
|
okamzita platba pri zalozeni uctu stolu
|
||||||
|
unblock uctu po ukonceni PosDialogu bez akce OK
|
||||||
|
osetri ukladani uctu bez polozek pri splitu
|
||||||
|
kdyz prevadis na ucet, kde uz neco je -> zavedena novy endpoint merge_ucet
|
||||||
|
prevody to co vyberes zustava, to co ma zustat se prevadi??? vyreseno, ale chce to trochu ucesat
|
||||||
|
pridan do vsech operaci s ucty filtr na id_kas
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
############################################################
|
||||||
|
# INSTALACE POKLADNY NA UBUNTU (PYTHON 3.12)
|
||||||
|
############################################################
|
||||||
|
sudo apt update
|
||||||
|
sudo apt upgrade -y
|
||||||
|
|
||||||
|
# -- INSTALACE PYTHON 3.12 A VENV
|
||||||
|
|
||||||
|
sudo apt install -y \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
python3-venv \
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
# -- KONTROLA VERZE PYTHONU
|
||||||
|
python3 --version
|
||||||
|
|
||||||
|
# -- ZAKLADNI SYSTEMOVE BALICKY (obvykle není potřeba)
|
||||||
|
sudo apt install -y \
|
||||||
|
build-essential \
|
||||||
|
pkg-config \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
zip \
|
||||||
|
unzip
|
||||||
|
|
||||||
|
# -- KNIHOVNY POTREBNE PRO KIVY
|
||||||
|
sudo apt install -y \
|
||||||
|
libgl1-mesa-dev \
|
||||||
|
libgles2-mesa-dev \
|
||||||
|
mesa-utils \
|
||||||
|
libglib2.0-0 \
|
||||||
|
libmtdev1 \
|
||||||
|
xclip \
|
||||||
|
xsel \
|
||||||
|
libjpeg-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libfreetype6-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
libffi-dev \
|
||||||
|
libssl-dev \
|
||||||
|
libsqlite3-dev
|
||||||
|
|
||||||
|
# -- VYTVORENI SLOZKY PRO POKLADNU, aktivace venv
|
||||||
|
mkdir -p ~/pokladna
|
||||||
|
cd ~/pokladna
|
||||||
|
python3 -m venv k312
|
||||||
|
source k312/bin/activate
|
||||||
|
|
||||||
|
# -- UPGRADE PIP, dulezite!!!
|
||||||
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
# -- INSTALACE KIVY
|
||||||
|
pip install kivy
|
||||||
|
|
||||||
|
# -- BALICKY PRO POKLADNU
|
||||||
|
pip install \
|
||||||
|
pydantic \
|
||||||
|
fastapi \
|
||||||
|
uvicorn \
|
||||||
|
requests \
|
||||||
|
pillow \
|
||||||
|
qrcode \
|
||||||
|
|
||||||
|
|
||||||
|
# -- VYTVORENI STARTOVACIHO SKRIPTU
|
||||||
|
cat > start_pokladna.sh <<'BASH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
cd ~/pokladna
|
||||||
|
source venv/bin/activate
|
||||||
|
python kivy_app.py
|
||||||
|
BASH
|
||||||
|
|
||||||
|
chmod +x start_pokladna.sh
|
||||||
|
|
||||||
|
# -- SPUSTENI POKLADNY
|
||||||
|
./start_pokladna.sh
|
||||||
|
|
||||||
|
deactivate
|
||||||
|
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
Verze s Kivy (dole popis principu)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
v posdialogu ostava dorobit:
|
||||||
|
- doplnit do action_panela zlavu na polozku a zmenu spravy
|
||||||
|
|
||||||
|
Uzavierky
|
||||||
|
Jazyky
|
||||||
|
Prehlad spotreby
|
||||||
|
Zlavy na polozky
|
||||||
|
Vklady, vybery
|
||||||
|
Uhrada pohladavky
|
||||||
|
Nastavenie dostupnosti kariet
|
||||||
|
Okno na nastavenie dat v config.json - aby sa dala vybrat kasa, s ktorou chceme pracovat
|
||||||
|
Aktualizacia cennik bez restartu server a appky
|
||||||
|
Cook
|
||||||
|
Bazen
|
||||||
|
LoyalMan
|
||||||
|
Rajonovy rezim a uzavierky casnikov
|
||||||
|
Prava casnikov
|
||||||
|
|
||||||
|
|
||||||
|
pod s buttonem pod zpet, nevim co s tim
|
||||||
|
- pokud nechces uzaverku blokovat spustenym terminálem, oprav to zde
|
||||||
|
server_sqlite.py
|
||||||
|
@app.post("/closure/save/",response_model=server_clsrep.ClosureReportOut)
|
||||||
|
def save_closure_report(
|
||||||
|
- odstran chybu co popsal Milan v mailu (pro zuseni uzaverky kdyz vyberes stejny ucet k uzaverce to spadne)
|
||||||
|
- sleva na položku (cena, cena puv)
|
||||||
|
(do ceniku pridat slovnik atributu, atribut a hodnota, zde max sleva napr. 0)
|
||||||
|
- dopln na stale podrzeni butonu pro markovani do menu sleva na polozku
|
||||||
|
- dodělat bar rezim s automatickym odhlasenim po nastavene dobe
|
||||||
|
- otestuj spec. touche při markovani a editaci uctu
|
||||||
|
- v posdialog se pouziva _popup_info z controlleru a jsou tam ještě definovany nejaky spec. sjednot to
|
||||||
|
- menu uzaverky (uzaverka s doplnenim id_ucty), meziuzaverka, tisk kopie uzaverky, mazani poslední uzaverky, posun uzaverky?
|
||||||
|
- do posdialog a numpad udelej cteni RS232 a klavesnice pro vstup externich ctecek
|
||||||
|
- otestuj prihlaseni stejne id_kas se stejnym client_id
|
||||||
|
- zjistit při pokusu zablokovat ucet ke stornu když probiha jeho storno na jinem terminalu
|
||||||
|
- do config.json pridat parametry pro velikost accountselect a posdialog (zejména počet buttonu v matici)
|
||||||
|
- upravit format uctu a bonu na terminalu
|
||||||
|
- zobrazeni konfiguracnich parametru při neuspesnem startu
|
||||||
|
|
||||||
|
Hotovo:
|
||||||
|
===== 072_8_Kivy ====================================================================================================
|
||||||
|
Bar
|
||||||
|
Limity
|
||||||
|
- doplnena tabulka fooddat
|
||||||
|
|
||||||
|
Akceptujem parametre z def.suboru:
|
||||||
|
IS_LIMSPRA - ak je nastaveny connect na postgresql v centralnom setupe
|
||||||
|
===== 071_8_Kivy ====================================================================================================
|
||||||
|
- prvy nastrel tlace. Kasa uklada tlacove joby do fronty v tabulke print_jobs. Zapisuje tam vsetky joby, ktore nemaju tlacit na afs.
|
||||||
|
- k tlaciarni je mozne vo foode nadefinovat sablonu, cez ktoru sa maju tlacit bony aj ucty. su to podobne jinja2 subory ako pouzival foodie. kasa potom hlada bud nastavenu sablonu od tlaciarne, alebo default sablonu, alebo ked nic nenajde vytlaci jednoduchy bon bez formatovania. Rovnako sa postupuje pri tlaci uctov.
|
||||||
|
- komunikacia s bank terminalmi je podmienena nastavenim priznaku v druhu platby a v tlaciarni, na ktoru sa ide tlacit. potom podla toho aky terminal je k tlaciarni priradeny, vola sa obsluha terminalu. zatial som oskusal slovenske AFS a pripraveny je Besternom, tak, ako ho napisal Pepino. Ten som ale nevzskusal, lebo ho tu nemam
|
||||||
|
- pribudol local_print_agent ako samostatny script, ktory sa moze spustit na windowse/linuxe v lokalnej sieti, alebo moze byt urobeny ako samostatna androidova appka. ten bude zo servera vytahovat pripravene joby a tlacit ich. skusal som to u nas na raw printeroch. pocita aj s cups tlaciarnami
|
||||||
|
- tlace dotiahnute aj v okne na kopie a storna uctov
|
||||||
|
- storno uctu s platbou kartou je riadene parametrom terminal_storno rovnako ako bolo vo foodie
|
||||||
|
- pre nefiskalne ucty je nastavitelne v def.subore, ci sa ucet moze aj nevytlacit
|
||||||
|
- menu v accountselet (storno s vraceni na ucet, storno polozek z uctu)
|
||||||
|
- rozmysli tiskarny bonu (muzou byt v setupu sklad -> bon printer)
|
||||||
|
- zaokrouhlovani uctu, vracet sumu zaokrouhleni
|
||||||
|
- tisky bonu do kuchyne (musíš pridat tiskárnu do ceniku, vazbu sklad printer do setupu)
|
||||||
|
Akceptujem parametre z def.suboru:
|
||||||
|
DEF_CENHLA
|
||||||
|
OBJEDNAVKA_TLACITKO1
|
||||||
|
OBJEDNAVKA_TLACITKO2
|
||||||
|
OBJEDNAVKA_TLACITKO3
|
||||||
|
IS_CHOD
|
||||||
|
IS_HOST
|
||||||
|
IS_TRETINY
|
||||||
|
IS_STVRTINY
|
||||||
|
KC_SPART
|
||||||
|
MENU_SPART
|
||||||
|
CARD_PAY_NO_TERM
|
||||||
|
BAR_PAY_IN_CASH
|
||||||
|
ZKR_MENA
|
||||||
|
TERMINAL_STORNO
|
||||||
|
NKOP_EDIT
|
||||||
|
REPRINT_CURRENT_CLOSURE_BILL
|
||||||
|
REPRINT_PAST_CLOSURE_BILL
|
||||||
|
RASTR_HOT
|
||||||
|
IS_HORSKUP
|
||||||
|
POSTGRES_ENABLED
|
||||||
|
===== 070_8_Kivy ====================================================================================================
|
||||||
|
- v platobnom okne doplnena moznost vybrat viacero zliav. nasledne sa vola recalculate, ako metoda, ktora cely ucet prepocita. ide sa v poradi - zmena cenovej hladiny, absolutne zlavy, percentualne zlavy, a potom jednotlive platby
|
||||||
|
- dodělej logiku ke slevam (absolutni, procentuelni, na položku a atributy nodiscountv ceniku)
|
||||||
|
- do uctu/UcPol dodělat cena_puv, vyndat mena (markuje se jen zakladni mene). Nebo prepocet dle kurzu? Zatim to tam nechat.
|
||||||
|
- presun messages ze setupu do ceniku
|
||||||
|
- doplnena tabulka bankterm
|
||||||
|
- v tabulke prndef doplneny stlpec id_term
|
||||||
|
- do parametrov doplnene is_chod a is_host. Da sa nimi vypnut praca s chodmi a hostami)
|
||||||
|
- doplnena tabulka clients - applikacia si tu uklada cislo posledne vybranej tlaciarne a miestnosti pre kazdy terminal, aby to pri dalsom spusteni vedela pouzit
|
||||||
|
===== 069_8_Kivy ====================================================================================================
|
||||||
|
- doplnit predvolene sposoby platby nie iba hotovost
|
||||||
|
- Platba vybranych poloziek a Platba vsetkeho podla toho ci su naklikane nejake polozky, alebo nie
|
||||||
|
- niekde zobrazit predvolenu cenovu hladinu
|
||||||
|
- doplnit volbu tlaciarne, kam sa budu tlacit ucty
|
||||||
|
- upraveny platobny formular - najprv sa zadaju zlavy, potom sa vyberaju platby
|
||||||
|
- vyriesene dotaz_re, dotaz_st, dotaz_ho / oskusana platba na Hores, Fidelio, Previo. Pripravene aj Mews a Protel
|
||||||
|
|
||||||
|
v data:
|
||||||
|
doplnene tabulky na nastavenie recepcie a rastrov pre recepciu
|
||||||
|
v cenniku doplneny c_druh, aby som veel posielat na recepciu
|
||||||
|
v uctoch doplnene data uveru a hoteloveho uctu, doplneny stlpec c_uzaverka
|
||||||
|
===== 068_8_Kivy ====================================================================================================
|
||||||
|
- v PosDialogu je zjednotene otvaranie modalnych okien do jedneho modalmanagera, ktory spravuje aj vstupy z klavesnice
|
||||||
|
- prihlasenie klavesnicou, ked nemam numpad robi problem, lebo shift sa berie ako samostatna klavesa
|
||||||
|
- v hladani doplnit aj hladanie podla kodov a eanov
|
||||||
|
===== 067_8_Kivy ====================================================================================================
|
||||||
|
- v objednavke je mozne z klavesnice zadat kod, ci ean a ked sa najde, nablokuje sa. funguje aj 2050*10.
|
||||||
|
- tlacitko vyber vsetko nahradaene tlacitkom Hladaj. Ukaze sa klavesnica na zadanie retazca. Podla zadaneho textu sa filtruje cennik a dohladavaju sa kalkulacie, ktore obsahuju zadany text
|
||||||
|
- login screen - heslo je mozne zadat aj z klavesnice
|
||||||
|
===== 066_8_Kivy ====================================================================================================
|
||||||
|
- praca s chodmi a hostami, presuny medyi chodmi, hostami a stolmi. Oynacenie poloziek chodu, hosta, ...
|
||||||
|
- action panel ponuka pracu s oznacenymi polozkami objednavky
|
||||||
|
- jsou-li vyplneny ceny2 a cena3, pouzij ji pro 1/2 a 1/3 porce
|
||||||
|
- chody vyreseny (ještě do tisku)
|
||||||
|
- povinne zprávy při markovani kodem
|
||||||
|
- osetrene ceske aj slovenske hesla (12, resp. 20 znakov, aj adm hesla v oboch formatoch)
|
||||||
|
- doplnene spracovanie atributov polozky "volnacena","pohladavka","fstmenu","vazena"
|
||||||
|
- osetrene spravy - povinne/nepovinne priradene k itemu, aj vseobecne spravy zo setupu a manualna sprava vratane sw klavesnice
|
||||||
|
- long press na menu vyvola okno na zadanie poctu porcii, zlomkov a sprav
|
||||||
|
- doplnene chody a hostia - na long press aj s pomenovanim
|
||||||
|
- vpravo hore tlacitko na oznacenie/odznacenie vsetkeho
|
||||||
|
zmeny v data:
|
||||||
|
- UserLoginIn - doplneny kas
|
||||||
|
- Perm - doplnene jazykove mutacie
|
||||||
|
- doplnene PolozkyFstMenu, FstMenu, FstMenuKasa, UserPermission, PaymentPermission, DiscountPermission, LevelPermission
|
||||||
|
- UserIn - doplnene heslo_karta, user_id, is_admin, permits, payments, discounts, levels
|
||||||
|
- UserOut - doplnene user_id, is_admin, payments, discounts, levels - mozno tu chyba este permits
|
||||||
|
- UserLoginOut - doplnene user_id, is_admin, payments, discounts, levels, permits
|
||||||
|
- UCPol - pridane zpravy - budeme ich potrebovat kvoli cookovi, uhradam pohladavok, pripadne aj zmena spravy k uz nablokovanej polozke
|
||||||
|
- UcPolEdit - zpravy sa dedia od UcPol
|
||||||
|
|
||||||
|
===== 063_8_KivyRq/059_8_KivyAPI ====================================================================================================
|
||||||
|
- pokud udelas zpet z menu privátních zprav dlouhe, namarkuje se ti polozka
|
||||||
|
- vyber vse -> změna cenove hladiny -> uloz = položky zmizi z uctu (opraveno v Posdialog by Petr 21.4.)
|
||||||
|
- pokud při submenu na buttonu položky v leve casti objednávky (dlouhy stisk) (opraveno v PosDialog by Petr 22.4.)
|
||||||
|
===== 061,2_8_KivyRq/059_8_KivyAPI ====================================================================================================
|
||||||
|
- nektere obecne konstanty pro beh frontendu presunty do modulu konstanty
|
||||||
|
- pri neuspesnem startu umozni zadat IP API serveru
|
||||||
|
===== 060_8_KivyRq/059_8_KivyAPI ====================================================================================================
|
||||||
|
- pokud edituji definci stolu, nejde ulozit
|
||||||
|
===== 059_8_Kivy ====================================================================================================================
|
||||||
|
- dodělej endpoint pro nahrani uzivatelu a permision (Milan_users.py)
|
||||||
|
===== 058_8_Kivy ====================================================================================================================
|
||||||
|
- opravena chyba pri vyberu defaultni hladiny (front end havaroval pri pokusu nastavit hladinu na prazdne misto ci link na jinou stranku)
|
||||||
|
- opraveno menu pro vyber hladin, pridam scroll (u polozky i defaultni) pro zobrazeni neomezeneho poctu hladin
|
||||||
|
- editor mapy stolu nyni umistuje stul vlevo nahore
|
||||||
|
- doplneno menu editoru stolu (nova mistnost, smaz mistnost, do menu stolu doplnen delete stolu)
|
||||||
|
- menu mistnosti jak v editoru tak pri vyberu mistnosti je nyni scrollovaci (nemomezeny pocet mistnosti)
|
||||||
|
- defautni id stolu je nyni tvoreno kombinaci jmena mistnosti a cisla stolu (zabranuje to nechtenemu sdileni uctu v ruznych mistnostech)
|
||||||
|
- automaticke zarovnavani stolu do mrizky
|
||||||
|
===== 057_8_Kivy ====================================================================================================================
|
||||||
|
- vzorovy program pro nahrani mapy stolu z foodu Milan_mapastolu
|
||||||
|
- mapa stolu a jednoduchy editor, ktery ji ulozi na server primo v pokladne
|
||||||
|
- endpoint na mapu stolu
|
||||||
|
===== 056_8_Kivy ====================================================================================================================
|
||||||
|
- do info v menu uzaverky doplneny info o verzi serveru, frontendu a jmenu aktualni database pouzivane serverem
|
||||||
|
- endpoint na ucty co nejsou v uzaverce (test/vzor milan_ucty_notinclsrep)
|
||||||
|
- hotovo cena_puv
|
||||||
|
- v uctech je cislo skladu pro odtezovani
|
||||||
|
- dodělej endpoint pro nahrani mapy stolu (test/vzor milan_mapastolu)
|
||||||
|
- do info zobraz verzi front endu i serveru (server to muze vrátit při prihlaseni)
|
||||||
|
===== 055_8_Kivy ====================================================================================================================
|
||||||
|
- normalni platba, pokud je něco vybrano take zaplati jen vybrane (ale korektne, zbytek uctu tam zustane). Pak nemá smysl platba vybraneho?? nema
|
||||||
|
- vyndej ze server_sqlite heartbeat, at to muzes distribuovat oddelene
|
||||||
|
===== 054_8_Kivy ====================================================================================================================
|
||||||
|
- do serveru doplneny 2 endpointy pro nacteni uzaverky z FOODu. Vzor pouziti Milan_nacti_uzaverky
|
||||||
|
- mas-li oznacene nejake položky na uctu a udelas platbu vseho hotove, zaplati se vybrane a zbytek uctu zmizi
|
||||||
|
- lze definovat buttony pro ruzne sirky
|
||||||
|
- opravena migrace v DB pro pridani sirky button matice
|
||||||
|
- exituji 2 typy zprav. obecne (jdou pripojit ke kazde polozce) a privatni (jdou jen k te polozce, co je ma uvedene v ceniku). Privatni se mohou delit na povinne a ostatni. Obecne se aktivuji dlouhym stiskem na nazev v namarkovane polozce uctu (jsou tam i vsechy zpravy mazat s vyjimkou povinnych), povinne se musi automaticky zadat pri markovani. Pokud je aktivovano Fastitemmenu (dlouhy stisk na button v matici vlevo) a polozka obsahuje povinnou zpravu, nejprve se Zada povinna zprava a az potom se objevi FastItemMenu.
|
||||||
|
- povinne zprávy při markovani jsou vyreseny ale nemely by jit smazat a co s dlouhym stiskem?- implementuj do markovani nove data od Milana (Eany, povinne zprávy, permision pro markovani, atributy)
|
||||||
|
- uprav FastMenuItem pro smyslupne markovani (vic voleb), mazani zvoleného zvyrazneno
|
||||||
|
- vic zprav k jedne polozce, zprávy jdou i mazat (po jedne i všechny)
|
||||||
|
- na serveru je automaticka migrace jsonu v ceniku s propisem do DB (nemigracni verze je 048_8_kivy, kdyby to moc zdrzovalo). nove pole musi mit default hodnotu, aby Pydantic nezarval pred uskutecnenim migrace
|
||||||
|
- při prepnuti cenove hladiny nejsou na matici pro markovani aktualni ceny
|
||||||
|
- doplneny dluhy stisk na levou matici
|
||||||
|
- zmen markovani kodem dle atributu kod (nyní je to id_card)
|
||||||
|
- uprav cenik pro import z Food (jen rozsirit pro kod misto id_card, eany, spec zprávy prirazene k polozce (povinne/nepovinne) a atributy
|
||||||
|
- uprav dle vzoru z data.py rutiny pro zapis setupu (v setupu obecne zprávy)
|
||||||
|
- uprav dle vzoru z data.py rutiny pro zapis ceniku vcetne vzoru pro Milana
|
||||||
|
- při pocitani uzaverky musíš byt jediny zivy terminal (takze zadny ucet neni blokovan), nevim jestli je to nutne
|
||||||
|
- v ceniku je pos_pc resp. pos_mb misto prostého tuple list[tuple], coz umozni jednu položku umistit na libovolny počet stranek pomoci jednoho zaznamu v ceniku
|
||||||
|
- je-li vybran nejaky počet kusu (nejvic leve pole v položkách uctu), musíš při skrtani zprava do leva kontrolovat, aby vybrany počet kusu nebyl vetsi nez namarkovany
|
||||||
|
- zkontroluj, tisknou-li se bony do kuchyne nejen při operaci uloz, ale i při split, platba, castecna platba. Proste vždy když se objevi neodeslana položka na ucte. Když namarkujes nejake položky a soucasne nejake vyberes ke stornu a udelas storno polozek tak se opravdu vytisknou bony na neodeslane a storna na jiz předtím odeslane.
|
||||||
|
- na dlouhy stisk nove namarkovane polozky se pride message ze setupu
|
||||||
|
- uzaverkoveho reportu pridej seznam otevrenych uctu se sumou
|
||||||
|
- při uzaverce, když je pusteny jiny terminal, vznikne neosetreny runtimeerror
|
||||||
|
- cenova hladina jde menit i na odeslanych polozkach
|
||||||
|
- pri prepnuti defaultni hladiny se prepisi ceny na buttonech
|
||||||
|
- uzaverka zjevne pocita poslední ucet z minule uzaverky jako první nasledujici (prekryvaji se).
|
||||||
|
- serad uzavrene ucty v menu accountselect dle cisla uctu
|
||||||
|
- nabizej jen cisla uctu po poslední uzaverce
|
||||||
|
- ma generovani noveho cisla na serveru ochranu proti preteceni? Ma. Vyreseno.
|
||||||
|
- dodelana ochrana proti prihlaseni stejne id_ka se stejnym clientem, po logoutu se odstarni heartbeats
|
||||||
|
- uzaverka musí mit číslo uzaverky pro konkretni id_kas
|
||||||
|
- vylepsit popisky buttonu uctu jak v accountselect tak v closed_accountselect
|
||||||
|
- proved kontrolu odblokovani uctu po stornech (v closed_accountdialogu se to neobjevi, je to další atribut)
|
||||||
|
- funguje storno vcetne ochrany druhého stornovani a stornovani storna, funguje barevne rozliseni storen a stornovanych uctu
|
||||||
|
- hotova operace tisk kopie uctu, na serveru a v api_call je operace unblock dle ucisla
|
||||||
|
- operace v menu accountselect ted konci v controlleru v handle_closed_accountselect, zbyva dodělat jen z nej volane funkce
|
||||||
|
- spolecna rodicovska trida pro accountselect a closed_accountselect, na server pridano do jsonu uctu total_base_currency (pri sumdph spocte total v zakladni mene)
|
||||||
|
- hotove zobrazeni zaplacenych uctu k operacim v menu z accountselect
|
||||||
|
- pridan info pasek na TOP Posdialogu
|
||||||
|
- změna v refreshi accountselect, ted bezi porad dokud je activni i pod jinými okny
|
||||||
|
- do menu konfiguracni parametry (config.json) a take tisk vlastní IP adresy
|
||||||
|
- format uctu snesitelny
|
||||||
|
- doplneny všechny informace do uzavrenych uctu
|
||||||
|
- tisk uctu z Windows a RPI Debian na TCP printer funguje
|
||||||
|
- konfiguracni parametry (Android, Debian, Windows) -> vyzkouseno Windows, RPI Debian
|
||||||
|
- zablokovany ucet ma jinou barvu
|
||||||
|
- hotovy preview uctu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pouziva virtualni prostředí v_kivy nebo v311 na kivy UI (nutne zejmena na RPI debianu)
|
||||||
|
spousteni primo pod pythonem
|
||||||
|
v_kivy/Scripts/python.exe
|
||||||
|
idealni Python je v 3.11
|
||||||
|
|
||||||
|
pouzite externi moduly:
|
||||||
|
pydantic, pillow, qrcode, requests, fastapi, uvicorn, kivy
|
||||||
|
|
||||||
|
|
||||||
|
Zakladni princip.
|
||||||
|
Klient komunikuje s API serverem pomoci API callu. Všechny API calls jsou ulozeny v api_call.py
|
||||||
|
Je tam i mechanizmus pridelovani tokenu, autentifikace a identifikace privatnich tabulek zakazky.
|
||||||
|
System rozeznava dva typy prihlaseni. 1. k zakazce, jmenem a heslem. Při uspesnem prihlaseni
|
||||||
|
dostane klient od servera token a refresh token, který jiz obsahuje i identifinaci zakazky a tim
|
||||||
|
i pristup k privatnim tabulkam zakazky. Klient provádí heartbeet (na jinem socketu), server ho zapisuje do centralni
|
||||||
|
tabulky heartbeetu s aktuálním casem. Pokud server narazi na lock uctu, zkontroluje heartbeet (id_kas a
|
||||||
|
terminalu) kasy, pokud je expirovan, nebere ho v úvahu.
|
||||||
|
Aplikace pouziva stale stejne 2 sockety, dokud nevypadnou na timeout nebo je server nezahodi. Prvni je
|
||||||
|
pro heartbeet, druhy pro chod frontendu (i ten provadi periodicke dotazy na otevrene ucty, pokud pokladna
|
||||||
|
neni odhlasena (cisnik)
|
||||||
|
Dale se po startu prihlasuje cisnik (operator), jen PINem. Cisnik/user pak dostane seznam tzv. permitu, ktere
|
||||||
|
jsou pouzity pro autentifikaci operaci s omezenym pristupem. Funguje klasicke denni heslo Alta.
|
||||||
|
Nektere operace serveru defaultne lockuji ucty (v parametrech lze potlacit)
|
||||||
|
V budoucnu se na serveru da do extra modulu vse co souvisi s pristupem k DB (nyní SQLite), takze
|
||||||
|
budou v modulech striktne oddeleny endpointy (routy) od DB operaci.
|
||||||
|
Klient je rozdelen na spousteci modul, který obsahuje tridu controller. Zde je veskera obchodni
|
||||||
|
logika, ktera pracuje s daty ve forme, ve ktere jsou ulozeny na serveru. Server i klient pouzivaji stejny modul
|
||||||
|
data, kde jsou zakladni datove modely (cenik, ucet, setup...)
|
||||||
|
Z controlleru se vola modul accountselect (zde se zobrazuji otevrene ucty a zakladni menu pokladny, ve vrchni
|
||||||
|
casti je bud widget s otevrenymi stoly nebo mapa stolu zobrazene mistnosti.
|
||||||
|
Jeden stul muze byt zobrazen v nekolika mistnostech a mapa muze byt spolecna pro vice pokladen
|
||||||
|
Zatim neuzvazuji o sdileni stolu jednotlivymi pokladnami
|
||||||
|
Při vybrani uctu se z modulu posdialog instancuje trida posdialog. Ta pracuje s upravenymi definicemi
|
||||||
|
uctu, které jsou rozsireny o vlastnosti umožňující editaci (nektere jiné vlatnosti zase chybi)
|
||||||
|
Po ukonceni posdialogu se do controlleru vraci u_main, u_sec, a operace. Typicky u_main obsahuje
|
||||||
|
zbytek původního uctu po operaci, u_sec položky vybrane k operaci.
|
||||||
|
Po provedeni operace controller pomoci api calls ulozi novy stav na server.
|
||||||
|
Nektere operace (platba, prevody mezi ucty...), volaji další okna (widgety), jako například payment.
|
||||||
|
V soucasne chvili klient nepouziva k persistenci nic jiného, nez serverove API calls. Tzn., pokud se něco stane,
|
||||||
|
po restartu klienta dostaneme stav pred začátkem rozpracovane operace.
|
||||||
|
V budoucnu predpokladam po x vteřinách update rozpracovane operace na server. To ale trochu koliduje
|
||||||
|
s pravidlem, ze jediny kdo operuje s daty na serveru je controller. Nicmene Posdialog není modalni, nebude
|
||||||
|
to takovy problem screen managerem pustit update stavu. V podstate jde je o rozmarkovany ucet, mozna vyber
|
||||||
|
v posdialogu.
|
||||||
|
Krome accountselect dialogu pro vybrani otevreneho uctu existuje jeste closed_accountselect dialog, ktery
|
||||||
|
slouzi k vyberu uzavrenych uctu (kopie, storna apod.) Oba tyto dialogy maji stejneho rodice.
|
||||||
|
V soucasne chvili je vyzkousena portace na Windows, Linux (jak 86 tak ARM procesory) a MacOS. System vcetne servera dobře funguje na
|
||||||
|
Rabsberry, napr. P400. Samozrejme je vyzkousen i provoz přes HotSpot a VPN. Server na Hluce, klient v Motole.
|
||||||
|
Pro Android je s Kivy k dispozici dozer, jeste jsem nezkousel.
|
||||||
|
Ve chvili, kdy zacnes editovat ucet ktery neexistuje se serveru vytvori dummy a zablokuje se. Tim se predchazi aby nedoslo k soucasne
|
||||||
|
editaci stejneho noveho uctu.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ToDo:
|
||||||
|
- vyhazej ze serveru endpointy pro users, které nejsou potřeba
|
||||||
|
- rozdelit server na endpointy a DB operace
|
||||||
|
- implementuj pojmenovane stuly
|
||||||
|
- automaticky test
|
||||||
|
-vice pokladen, vice terminalu
|
||||||
|
-blokace, release
|
||||||
|
-relogin, refresh token
|
||||||
|
-start s novou databazi
|
||||||
|
- zkus jinou databazi (postgres nebo DuckDB)
|
||||||
|
- parametricky prohozeni ucty a matici v PosDialog z prave strany doleva nebo nahore a dole (vzajemne se prekryvajici)
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#Konstanty
|
||||||
|
from kivy.metrics import dp
|
||||||
|
|
||||||
|
SCREEN_LOGIN = "login"
|
||||||
|
SCREEN_LOGIN_USER = "login_user"
|
||||||
|
SCREEN_ACCOUNT = "account"
|
||||||
|
SCREEN_POS = "pos"
|
||||||
|
|
||||||
|
MAX_LOGIN_FAILS = 3 # nebo treba 5
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://127.0.0.1:8000",
|
||||||
|
"refresh_url": "http://127.0.0.1:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "",
|
||||||
|
"bon_printer1": "",
|
||||||
|
"bon_printer2": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- ACCOUNTSELECT
|
||||||
|
COLS = 7
|
||||||
|
BTN_W = dp(150)
|
||||||
|
BTN_H = dp(120)
|
||||||
|
SP = dp(10)
|
||||||
|
PAD = dp(10)
|
||||||
|
#posdialog
|
||||||
|
# ---- POSDIALOG parametry buttonu matice polozek
|
||||||
|
MENU_COLS = 4
|
||||||
|
MENU_ROWS = 5
|
||||||
|
ACC_BTN_W = dp(110)
|
||||||
|
MENU_BTN_W = dp(70)#dp(130)
|
||||||
|
MENU_BTN_H = dp(90)
|
||||||
|
BOTTOM_BTN_H = dp(60)
|
||||||
|
# --- parametry uctu
|
||||||
|
ACC_QTY_W = dp(64) # pro "999/2" (6 znaků + rezerva)
|
||||||
|
ACC_PRICE_W = dp(88) # cena
|
||||||
|
ACC_ROW_H = dp(44)
|
||||||
|
|
||||||
|
API_TIMEOUT = 5
|
||||||
|
API_RETRIES = 1
|
||||||
|
API_DELAY = 0.5
|
||||||
|
|
||||||
|
|
||||||
|
HEART_BEAT:int = 10
|
||||||
|
|
||||||
|
# -------------------------------
|
||||||
|
# --- zaznam v databazi uzivatelu
|
||||||
|
#--------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://127.0.0.1:8000",
|
||||||
|
"refresh_url": "http://127.0.0.1:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"base_url": "http://127.0.0.1:8000",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"id_kas": "07",
|
||||||
|
"client_id": "print-agent-07",
|
||||||
|
"agent_id": "print-agent-07",
|
||||||
|
"printers": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
import argparse
|
||||||
|
import getpass
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
os.environ.setdefault("KIVY_NO_ARGS", "1")
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import data
|
||||||
|
from server_sqlite import process_print_job
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("local_print_agent")
|
||||||
|
|
||||||
|
|
||||||
|
class AgentApiClient:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
base_url: str,
|
||||||
|
client_id: str,
|
||||||
|
id_kas: str,
|
||||||
|
username: str,
|
||||||
|
password: str,
|
||||||
|
user: str = "",
|
||||||
|
):
|
||||||
|
self.base_url = base_url.rstrip("/")
|
||||||
|
self.client_id = client_id
|
||||||
|
self.id_kas = id_kas
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.user = user
|
||||||
|
self.token = ""
|
||||||
|
self.refresh_token = ""
|
||||||
|
self.session = requests.Session()
|
||||||
|
|
||||||
|
def _headers(self) -> dict:
|
||||||
|
headers = {"X-Client-ID": self.client_id}
|
||||||
|
if self.token:
|
||||||
|
headers["Authorization"] = f"Bearer {self.token}"
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def _refresh_access_token(self) -> bool:
|
||||||
|
if not self.refresh_token:
|
||||||
|
return False
|
||||||
|
response = self.session.post(
|
||||||
|
f"{self.base_url}/refresh/",
|
||||||
|
headers={"X-Client-ID": self.client_id},
|
||||||
|
json={"refresh_token": f"Bearer {self.refresh_token}"},
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
return False
|
||||||
|
payload = response.json()
|
||||||
|
self.token = payload.get("access_token") or payload.get("token") or self.token
|
||||||
|
return bool(self.token)
|
||||||
|
|
||||||
|
def request(self, method: str, endpoint: str, **kwargs):
|
||||||
|
kwargs.setdefault("timeout", 30)
|
||||||
|
kwargs["headers"] = {**kwargs.pop("headers", {}), **self._headers()}
|
||||||
|
response = self.session.request(method, f"{self.base_url}{endpoint}", **kwargs)
|
||||||
|
if response.status_code == 401 and self._refresh_access_token():
|
||||||
|
kwargs["headers"] = {**kwargs.pop("headers", {}), **self._headers()}
|
||||||
|
response = self.session.request(method, f"{self.base_url}{endpoint}", **kwargs)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
try:
|
||||||
|
detail = response.json()
|
||||||
|
except ValueError:
|
||||||
|
detail = response.text
|
||||||
|
raise RuntimeError(f"{method} {endpoint} failed: {detail}")
|
||||||
|
try:
|
||||||
|
return response.json()
|
||||||
|
except ValueError:
|
||||||
|
return response.text
|
||||||
|
|
||||||
|
def login(self) -> tuple[str, str]:
|
||||||
|
response = self.request(
|
||||||
|
"POST",
|
||||||
|
"/login/",
|
||||||
|
json={
|
||||||
|
"username": self.username,
|
||||||
|
"password": self.password,
|
||||||
|
"id_kas": self.id_kas,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.token = response["access_token"]
|
||||||
|
self.refresh_token = response["refresh_token"]
|
||||||
|
return response.get("version_API", ""), response.get("database_name", "")
|
||||||
|
|
||||||
|
def claim_jobs(self, *, agent_id: str, printers: list[str], limit: int) -> list[data.PrintJob]:
|
||||||
|
payload = data.PrintJobClaimRequest(
|
||||||
|
id_kas=self.id_kas,
|
||||||
|
agent_id=agent_id,
|
||||||
|
printers=printers,
|
||||||
|
limit=limit,
|
||||||
|
).model_dump(mode="json")
|
||||||
|
response = self.request("POST", "/print/jobs/claim/", json=payload)
|
||||||
|
return [data.PrintJob.model_validate(item) for item in response]
|
||||||
|
|
||||||
|
def update_job_status(
|
||||||
|
self,
|
||||||
|
job_id: int,
|
||||||
|
status: str,
|
||||||
|
*,
|
||||||
|
result: dict | None = None,
|
||||||
|
error: str = "",
|
||||||
|
) -> data.PrintJob:
|
||||||
|
payload = data.PrintJobStatusUpdate(
|
||||||
|
status=status,
|
||||||
|
result=result or {},
|
||||||
|
error=error or "",
|
||||||
|
).model_dump(mode="json")
|
||||||
|
response = self.request("POST", f"/print/jobs/{job_id}/status", json=payload)
|
||||||
|
return data.PrintJob.model_validate(response)
|
||||||
|
|
||||||
|
|
||||||
|
def _csv(value: str | None) -> list[str]:
|
||||||
|
return [item.strip() for item in str(value or "").split(",") if item.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def _load_config(path: str | None) -> dict:
|
||||||
|
if not path:
|
||||||
|
return {}
|
||||||
|
config_path = Path(path)
|
||||||
|
if not config_path.exists():
|
||||||
|
raise FileNotFoundError(f"Konfiguracny subor neexistuje: {config_path}")
|
||||||
|
return json.loads(config_path.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def _arg_value(args, config: dict, name: str, default=None):
|
||||||
|
value = getattr(args, name, None)
|
||||||
|
if value is not None and value != "":
|
||||||
|
return value
|
||||||
|
return config.get(name, default)
|
||||||
|
|
||||||
|
|
||||||
|
def build_client(args, config: dict) -> AgentApiClient:
|
||||||
|
password = _arg_value(args, config, "password", "")
|
||||||
|
if not password:
|
||||||
|
password = getpass.getpass("Heslo zakazky: ")
|
||||||
|
return AgentApiClient(
|
||||||
|
user=str(_arg_value(args, config, "user", "") or ""),
|
||||||
|
base_url=str(_arg_value(args, config, "base_url", "") or "").rstrip("/"),
|
||||||
|
client_id=str(_arg_value(args, config, "client_id", "") or ""),
|
||||||
|
id_kas=str(_arg_value(args, config, "id_kas", "") or ""),
|
||||||
|
username=str(_arg_value(args, config, "username", "") or ""),
|
||||||
|
password=str(password),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def process_once(
|
||||||
|
client: AgentApiClient,
|
||||||
|
*,
|
||||||
|
agent_id: str,
|
||||||
|
printers: list[str],
|
||||||
|
limit: int,
|
||||||
|
timeout: float,
|
||||||
|
) -> list[data.PrintJob]:
|
||||||
|
claimed = client.claim_jobs(
|
||||||
|
agent_id=agent_id,
|
||||||
|
printers=printers,
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
processed: list[data.PrintJob] = []
|
||||||
|
for job in claimed:
|
||||||
|
try:
|
||||||
|
client.update_job_status(job.id, "printing")
|
||||||
|
result = process_print_job(job, timeout=timeout)
|
||||||
|
processed.append(
|
||||||
|
client.update_job_status(
|
||||||
|
job.id,
|
||||||
|
"printed",
|
||||||
|
result=result,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.info("Vytlaceny job %s printer=%s", job.id, job.printer_no)
|
||||||
|
except Exception as exc:
|
||||||
|
next_status = "failed_final" if job.attempts >= job.max_attempts else "retry_pending"
|
||||||
|
logger.exception("Tlac jobu %s zlyhala, status=%s", job.id, next_status)
|
||||||
|
processed.append(
|
||||||
|
client.update_job_status(
|
||||||
|
job.id,
|
||||||
|
next_status,
|
||||||
|
error=str(exc),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return processed
|
||||||
|
|
||||||
|
|
||||||
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Lokalny print agent pre Pokladna print_jobs frontu.",
|
||||||
|
)
|
||||||
|
parser.add_argument("--config", help="Volitelny JSON konfiguracny subor.")
|
||||||
|
parser.add_argument("--base-url", dest="base_url", help="URL aplikacneho servera, napr. http://server:8000")
|
||||||
|
parser.add_argument("--username", help="Login zakazky.")
|
||||||
|
parser.add_argument("--password", help="Heslo zakazky. Ak chyba, agent sa opyta v konzole.")
|
||||||
|
parser.add_argument("--user", default="", help="Meno pouzivatela pre kontext API.")
|
||||||
|
parser.add_argument("--id-kas", dest="id_kas", help="Cislo pokladne pouzite pri prihlaseni agenta.")
|
||||||
|
parser.add_argument("--client-id", dest="client_id", default="", help="Client/terminal id agenta.")
|
||||||
|
parser.add_argument("--agent-id", dest="agent_id", default="", help="Identifikator agenta vo fronte.")
|
||||||
|
parser.add_argument("--printers", default="", help="Ciarkou oddeleny zoznam prn_no, ktore agent obsluhuje. Prazdne znamena vsetky tlaciarne zakazky.")
|
||||||
|
parser.add_argument("--interval", type=float, default=2.0, help="Pauza medzi cyklami v sekundach.")
|
||||||
|
parser.add_argument("--limit", type=int, default=10, help="Max pocet jobov na jeden cyklus.")
|
||||||
|
parser.add_argument("--timeout", type=float, default=10.0, help="Timeout jednej tlace v sekundach.")
|
||||||
|
parser.add_argument("--once", action="store_true", help="Spracuje jeden cyklus a skonci.")
|
||||||
|
parser.add_argument("--log-level", default="INFO", choices=["DEBUG", "INFO", "WARNING", "ERROR"])
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
args = build_parser().parse_args(argv)
|
||||||
|
logging.basicConfig(
|
||||||
|
level=getattr(logging, args.log_level),
|
||||||
|
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||||
|
)
|
||||||
|
config = _load_config(args.config)
|
||||||
|
client = build_client(args, config)
|
||||||
|
if not client.base_url or not client.username or not client.id_kas:
|
||||||
|
raise SystemExit("Chyba base-url, username alebo id-kas.")
|
||||||
|
if not client.client_id:
|
||||||
|
client.client_id = f"print-agent-{socket.gethostname()}"
|
||||||
|
agent_id = str(_arg_value(args, config, "agent_id", "") or client.client_id)
|
||||||
|
printers = _csv(_arg_value(args, config, "printers", ""))
|
||||||
|
|
||||||
|
version, database = client.login()
|
||||||
|
logger.info(
|
||||||
|
"Print agent prihlaseny: server=%s db=%s login_id_kas=%s agent=%s printers=%s",
|
||||||
|
version,
|
||||||
|
database,
|
||||||
|
client.id_kas,
|
||||||
|
agent_id,
|
||||||
|
printers or "*",
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
processed = process_once(
|
||||||
|
client,
|
||||||
|
agent_id=agent_id,
|
||||||
|
printers=printers,
|
||||||
|
limit=max(1, min(int(args.limit or 10), 100)),
|
||||||
|
timeout=max(1.0, float(args.timeout or 10.0)),
|
||||||
|
)
|
||||||
|
if processed:
|
||||||
|
logger.info("Spracovanych jobov: %s", len(processed))
|
||||||
|
if args.once:
|
||||||
|
return 0
|
||||||
|
time.sleep(max(0.2, float(args.interval or 2.0)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
raise SystemExit(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("Print agent ukonceny.")
|
||||||
|
raise SystemExit(0)
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
{
|
||||||
|
"app.name": "Pokladna",
|
||||||
|
"button.ok": "OK",
|
||||||
|
"button.cancel": "Zrušit",
|
||||||
|
"button.back": "Zpět",
|
||||||
|
"button.close": "Zavřít",
|
||||||
|
"button.pay": "Platba",
|
||||||
|
"button.pay_selected": "Platba\nvybraného",
|
||||||
|
"button.save": "Uložit",
|
||||||
|
"button.search": "Hledat",
|
||||||
|
"button.code": "Kódem",
|
||||||
|
"button.loyalty_card": "Věrnostní karta",
|
||||||
|
"button.print": "Tisk",
|
||||||
|
"button.printer": "Tiskárna",
|
||||||
|
"button.execute_payment": "Provést platbu",
|
||||||
|
"button.receipt_preview": "Předúčet",
|
||||||
|
"button.send_email": "Poslat e-mailem",
|
||||||
|
"button.tip": "TIP",
|
||||||
|
"button.delete": "Smazat",
|
||||||
|
"button.storno": "Storno",
|
||||||
|
"login.title": "Přihlášení",
|
||||||
|
"login.password": "Heslo",
|
||||||
|
"login.invalid": "Neplatné přihlášení",
|
||||||
|
"account.bar": "Bar",
|
||||||
|
"account.open_tables": "Otevřené stoly",
|
||||||
|
"account.closed_receipts": "Účty",
|
||||||
|
"account.limits": "Limity",
|
||||||
|
"pos.action_panel": "Akce",
|
||||||
|
"pos.payment": "Platba",
|
||||||
|
"pos.item_storno": "Storno položky",
|
||||||
|
"pos.transfer_table": "Přesun na stůl",
|
||||||
|
"pos.message_for_item": "Zpráva pro položku",
|
||||||
|
"pos.price_level": "Cenová hladina",
|
||||||
|
"pos.vsetci": "Všichni",
|
||||||
|
"pos.guest": "Host",
|
||||||
|
"pos.course": "Chod",
|
||||||
|
"pos.table": "Stůl",
|
||||||
|
"pos.add": "Přidat",
|
||||||
|
"pos.prevod": "Převod",
|
||||||
|
"pos.prevod_bez_poloziek": "Nejsou vybrané žádné položky k převodu.",
|
||||||
|
"pos.uver_hlavicka": "Úvěrový záznam - výběr firmy",
|
||||||
|
"pos.uver_hint": "Hledat firmu, adresu, IČO, DIČ...",
|
||||||
|
"pos.uver_nova_firma": "Nová firma",
|
||||||
|
"pos.uver_nenajdena_firma": "Žiadna firma nevyhovuje hľadaniu.",
|
||||||
|
"pos.uverovy_zaznam": "Úverový záznam",
|
||||||
|
"pos.uver_firma": "Firma",
|
||||||
|
"pos.uver_adresa": "Adresa",
|
||||||
|
"pos.uver_ico": "IČO",
|
||||||
|
"pos.uver_icdph": "IČ DPH",
|
||||||
|
"pos.uver_dic": "DIČ",
|
||||||
|
"pos.uver_akcia": "Akcia",
|
||||||
|
"pos.uver_schvalil": "Schválil",
|
||||||
|
"pos.uver_povinne_meno": "Meno firmy je povinné.",
|
||||||
|
"pos.uver_povinne_schvalil": "Meno schvalovateľa je povinné.",
|
||||||
|
"pos.recepcia_vyber": "Výber recepcie",
|
||||||
|
"pos.recepcia_hladanie": "Hľadať recepciu ...",
|
||||||
|
"pos.recepcia_nenastavene": "Nie je nastavená žiadna recepcia",
|
||||||
|
"pos.recepcia_prefix": "Prefix",
|
||||||
|
"pos.recepcia_typ": "Typ",
|
||||||
|
"pos.recepcia_izba_skupina": "izba/skupina",
|
||||||
|
"pos.recepcia_hint": "Hľadať izbu, skupinu alebo hosťa...",
|
||||||
|
"pos.recepcia_cislo_izby": "Číslo izby",
|
||||||
|
"pos.recepcia_overit_izbu": "Overiť izbu",
|
||||||
|
"pos.recepcia_karta": "Card",
|
||||||
|
"pos.recepcia_ziadne_izby": "Žiadne izby na výber.",
|
||||||
|
"pos.recepcia": "Reception",
|
||||||
|
"pos.recepcia_no_charge": "Na túto izbu nie je možné naťažovať.",
|
||||||
|
"pos.recepcia_hladanie_hosta": "Hľadanie hosťa...",
|
||||||
|
"pos.recepcia_vyber_hosta": "Výber hosťa...",
|
||||||
|
"pos.recepcia_ziadny_host": "Žiadny hosť.",
|
||||||
|
"pos.hladat_polozku": "Hľadať položku...",
|
||||||
|
"pos.meno_hosta": "Jméno hosta",
|
||||||
|
"pos.nazov_chodu": "Název chodu",
|
||||||
|
"pos.sprava_pre": "Správa pre",
|
||||||
|
"pos.zadat_spravu": "Zadať správu",
|
||||||
|
"pos.sprava_povinna_musis_vybrat": "Musíte vybrať povinnú správu",
|
||||||
|
"pos.kasa": "Kasa",
|
||||||
|
"pos.terminal": "Terminál",
|
||||||
|
"pos.neplatna_cen_hladina": "Neplatná cenová hladina v nastavení zľavy.",
|
||||||
|
"pos.zlava": "sleva",
|
||||||
|
"pos.hladina_id": "hladina id",
|
||||||
|
"pos.neplatny_param_zlavy_dotaz_st": "Neplatný parameter zľavy pre dotaz_st.",
|
||||||
|
"pos.nenacitane_firmy": "Firmy pre úverový záznam sa nepodarilo načítať",
|
||||||
|
"pos.neulozena_firma": "Firmu sa nepodarilo uložiť",
|
||||||
|
"pos.recepcia_nenacitane": "Recepcie sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_izby_nenacitane": "Izby sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_nacitanie_karty": "Nacitanie hotelovej karty",
|
||||||
|
"pos.recepcia_cislo_karty": "Číslo karty",
|
||||||
|
"pos.recepcia_neoverena_karta": "Hotelovú kartu sa nepodarilo overiť",
|
||||||
|
"pos.recepcia_nenacitani_hostia": "Nepodarilo sa načítať hostí z izby",
|
||||||
|
"pos.recepcia_ziaden_host": "Na izbe sa nenašiel žiadny hosť.",
|
||||||
|
"pos.nie_je_co_platit": "Nie je čo platiť.",
|
||||||
|
"pos.def_cen_hlad": "Východzia cenová hladina",
|
||||||
|
"pos_polozka_xy_nie_je_v_cenniku": "Položka s kódem {code} nebyla nalezena v ceníku.",
|
||||||
|
"pos.kod_nenajdeny": "Kód nenájdený",
|
||||||
|
"pos.naozaj_zrusit_editaciu_uctu": "Naozaj chcete zrušiť editáciu účtu?",
|
||||||
|
"pos.neulozene_zmenu_sa_stratia": "Neuložené zmeny sa stratia",
|
||||||
|
"button.ano": "Ano",
|
||||||
|
"button.nie": "Ne",
|
||||||
|
"pos.zrusit_editaciu": "Zrušiť editáciu",
|
||||||
|
"pos.vyber_spravu_pre": "Vyber správu pre",
|
||||||
|
"pos.povinne_cislo_faktury": "Musíte zadať číslo faktúry",
|
||||||
|
"pos.pohladavka_musi_byt_sama": "Pohľadávku nie je možné kombinovať s inými položkami na jednom účte.",
|
||||||
|
"pos.uhrada_pohladavky": "Úhrada pohľadávky",
|
||||||
|
"pos.prazdny_ucet": "Účet je prázdny.",
|
||||||
|
"pos.nie_je_co_stornovat": "Nie je čo stornovať",
|
||||||
|
"pos.nic_nevybrane_na_storno": "Nie su vybrané žiadné položky na storno.",
|
||||||
|
"pos.limit_iba_cely": "Limitový stôl sa dá zaplatiť iba celý naraz.",
|
||||||
|
"pos.nevybrane_nic_na_platbu": "Nie su vybrané žiadné položky na platbu.",
|
||||||
|
"pos.vybrane_polozky_sa_nedaju_platit": "Vybrané položky sa nedajú pripraviť na platbu.",
|
||||||
|
"pos.chyba_cenika": "Chyba ceníku",
|
||||||
|
"pos.polozkanema_ziadnu_cenu": "Položka nemá žiadnu cenovú hladinu.\nNedá sa nablokovať.",
|
||||||
|
"pos.nedostupna_pre_hladinu": "Hladina {level} není pro tuto položku dostupná.\nPoužije se první dostupná cena.",
|
||||||
|
"pos.selected": "Vybráno",
|
||||||
|
"payment.step_discount": "Sleva / karta",
|
||||||
|
"payment.step_payments": "Platby",
|
||||||
|
"payment.amount_due": "K úhradě",
|
||||||
|
"payment.total": "Celková suma",
|
||||||
|
"payment.discount": "Sleva",
|
||||||
|
"payment.after_discount": "Suma po slevě",
|
||||||
|
"payment.paid": "Zaplaceno",
|
||||||
|
"payment.remaining": "Zůstává",
|
||||||
|
"payment.printer": "Tisk",
|
||||||
|
"payment.copies": "Kopií",
|
||||||
|
"payment.no_payment_selected": "Nebyla vybrána žádná platba.",
|
||||||
|
"receipt.title": "Účet",
|
||||||
|
"receipt.copy": "Kopie účtu",
|
||||||
|
"receipt.storno": "Storno účtu",
|
||||||
|
"receipt.payment_change": "Změna druhu platby",
|
||||||
|
"closed_receipts.title": "Účty",
|
||||||
|
"closed_receipts.current": "Aktuální účty",
|
||||||
|
"closed_receipts.date": "Datum",
|
||||||
|
"closed_receipts.print_copy": "Tisk kopie účtu",
|
||||||
|
"closed_receipts.change_payment": "Změnit platby",
|
||||||
|
"closed_receipts.enter_tip": "Zadání TIPu",
|
||||||
|
"limit.full_payment_only": "Limitový stůl lze zaplatit pouze celý najednou.",
|
||||||
|
"limit.transfer_mapping": "Přiřazení na limitový stůl",
|
||||||
|
"limit.courses": "Chody",
|
||||||
|
"limit.guests": "Hosté / hladiny",
|
||||||
|
"error.title": "Chyba",
|
||||||
|
"error.server": "Chyba serveru",
|
||||||
|
"common.empty": "Prázdné",
|
||||||
|
"common.none": "Žádné",
|
||||||
|
"common.yes": "Ano",
|
||||||
|
"common.no": "Ne"
|
||||||
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"app.name": "POS",
|
||||||
|
"button.ok": "OK",
|
||||||
|
"button.cancel": "Cancel",
|
||||||
|
"button.back": "Back",
|
||||||
|
"button.close": "Close",
|
||||||
|
"button.pay": "Payment",
|
||||||
|
"button.pay_selected": "Pay\nselected",
|
||||||
|
"button.save": "Save",
|
||||||
|
"button.search": "Search",
|
||||||
|
"button.code": "By code",
|
||||||
|
"button.loyalty_card": "Loyalty card",
|
||||||
|
"button.print": "Print",
|
||||||
|
"button.printer": "Printer",
|
||||||
|
"button.execute_payment": "Complete payment",
|
||||||
|
"button.receipt_preview": "Proforma",
|
||||||
|
"button.send_email": "Send by e-mail",
|
||||||
|
"button.tip": "TIP",
|
||||||
|
"button.delete": "Delete",
|
||||||
|
"button.storno": "Void",
|
||||||
|
"login.title": "Login",
|
||||||
|
"login.password": "Password",
|
||||||
|
"login.invalid": "Invalid login",
|
||||||
|
"account.bar": "Bar",
|
||||||
|
"account.open_tables": "Open tables",
|
||||||
|
"account.closed_receipts": "Receipts",
|
||||||
|
"account.limits": "Limits",
|
||||||
|
"pos.action_panel": "Actions",
|
||||||
|
"pos.payment": "Payment",
|
||||||
|
"pos.item_storno": "Void item",
|
||||||
|
"pos.transfer_table": "Move to table",
|
||||||
|
"pos.message_for_item": "Item message",
|
||||||
|
"pos.price_level": "Price level",
|
||||||
|
"pos.vsetci": "All",
|
||||||
|
"pos.guest": "Guest",
|
||||||
|
"pos.course": "Course",
|
||||||
|
"pos.table": "Table",
|
||||||
|
"pos.add": "Add",
|
||||||
|
"pos.prevod": "Move",
|
||||||
|
"pos.prevod_bez_poloziek": "Nejsou vybrané žádné položky k převodu.",
|
||||||
|
"pos.uver_hlavicka": "Úverový záznam - výber firmy",
|
||||||
|
"pos.uver_hint": "Hľadať firmu, adresu, IČO, DIČ...",
|
||||||
|
"pos.uver_nova_firma": "Nová firma",
|
||||||
|
"pos.uver_nenajdena_firma": "Žiadna firma nevyhovuje hľadaniu.",
|
||||||
|
"pos.uverovy_zaznam": "Úverový záznam",
|
||||||
|
"pos.uver_firma": "Firma",
|
||||||
|
"pos.uver_adresa": "Adresa",
|
||||||
|
"pos.uver_ico": "IČO",
|
||||||
|
"pos.uver_icdph": "IČ DPH",
|
||||||
|
"pos.uver_dic": "DIČ",
|
||||||
|
"pos.uver_akcia": "Akcia",
|
||||||
|
"pos.uver_schvalil": "Schválil",
|
||||||
|
"pos.uver_povinne_meno": "Meno firmy je povinné.",
|
||||||
|
"pos.uver_povinne_schvalil": "Meno schvalovateľa je povinné.",
|
||||||
|
"pos.recepcia_vyber": "Výber recepcie",
|
||||||
|
"pos.recepcia_hladanie": "Hľadať recepciu ...",
|
||||||
|
"pos.recepcia_nenastavene": "Nie je nastavená žiadna recepcia",
|
||||||
|
"pos.recepcia_prefix": "Prefix",
|
||||||
|
"pos.recepcia_typ": "Typ",
|
||||||
|
"pos.recepcia_izba_skupina": "izba/skupina",
|
||||||
|
"pos.recepcia_hint": "Hľadať izbu, skupinu alebo hosťa...",
|
||||||
|
"pos.recepcia_cislo_izby": "Číslo izby",
|
||||||
|
"pos.recepcia_overit_izbu": "Overiť izbu",
|
||||||
|
"pos.recepcia_karta": "Karta",
|
||||||
|
"pos.recepcia_ziadne_izby": "Žiadne izby na výber.",
|
||||||
|
"pos.recepcia": "Recepcia",
|
||||||
|
"pos.recepcia_no_charge":"Na túto izbu nie je možné naťažovať.",
|
||||||
|
"pos.recepcia_hladanie_hosta": "Hľadanie hosťa...",
|
||||||
|
"pos.recepcia_vyber_hosta": "Výber hosťa...",
|
||||||
|
"pos.recepcia_ziadny_host": "Žiadny hosť.",
|
||||||
|
"pos.hladat_polozku": "Hľadať položku...",
|
||||||
|
"pos.meno_hosta": "Meno hosťa",
|
||||||
|
"pos.nazov_chodu": "Názov chodu",
|
||||||
|
"pos.sprava_pre": "Správa pre",
|
||||||
|
"pos.zadat_spravu": "Zadať správu",
|
||||||
|
"pos.sprava_povinna_musis_vybrat": "Musíte vybrať povinnú správu",
|
||||||
|
"pos.kasa": "Kasa",
|
||||||
|
"pos.terminal": "Terminál",
|
||||||
|
"pos.neplatna_cen_hladina": "Neplatná cenová hladina v nastavení zľavy.",
|
||||||
|
"pos.zlava": "discount",
|
||||||
|
"pos.hladina_id": "hladina id",
|
||||||
|
"pos.neplatny_param_zlavy_dotaz_st": "Neplatný parameter zľavy pre dotaz_st.",
|
||||||
|
"pos.nenacitane_firmy": "Firmy pre úverový záznam sa nepodarilo načítať",
|
||||||
|
"pos.neulozena_firma": "Firmu sa nepodarilo uložiť",
|
||||||
|
"pos.recepcia_nenacitane": "Recepcie sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_izby_nenacitane": "Izby sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_nacitanie_karty": "Nacitanie hotelovej karty",
|
||||||
|
"pos.recepcia_cislo_karty": "Číslo karty",
|
||||||
|
"pos.recepcia_neoverena_karta": "Hotelovú kartu sa nepodarilo overiť",
|
||||||
|
"pos.recepcia_nenacitani_hostia": "Nepodarilo sa načítať hostí z izby",
|
||||||
|
"pos.recepcia_ziaden_host": "Na izbe sa nenašiel žiadny hosť.",
|
||||||
|
"pos.nie_je_co_platit": "Nie je čo platiť.",
|
||||||
|
"pos.def_cen_hlad": "Východzia cenová hladina",
|
||||||
|
"pos_polozka_xy_nie_je_v_cenniku": "Položka s kódem {code} nebyla nalezena v ceníku.",
|
||||||
|
"pos.kod_nenajdeny": "Kód nenájdený",
|
||||||
|
"pos.naozaj_zrusit_editaciu_uctu": "Naozaj chcete zrušiť editáciu účtu?",
|
||||||
|
"pos.neulozene_zmenu_sa_stratia": "Neuložené zmeny sa stratia",
|
||||||
|
"button.ano": "Yes",
|
||||||
|
"button.nie": "No",
|
||||||
|
"pos.zrusit_editaciu": "Zrušiť editáciu",
|
||||||
|
"pos.vyber_spravu_pre": "Vyber správu pre",
|
||||||
|
"pos.povinne_cislo_faktury": "Musíte zadať číslo faktúry",
|
||||||
|
"pos.pohladavka_musi_byt_sama": "Pohľadávku nie je možné kombinovať s inými položkami na jednom účte.",
|
||||||
|
"pos.uhrada_pohladavky": "Úhrada pohľadávky",
|
||||||
|
"pos.prazdny_ucet": "Účet je prázdny.",
|
||||||
|
"pos.nie_je_co_stornovat": "Nie je čostornovať",
|
||||||
|
"pos.nic_nevybrane_na_storno": "Nie su vybrané žiadné položky na storno.",
|
||||||
|
"pos.limit_iba_cely": "Limitový stôl sa dá zaplatiť iba celý naraz.",
|
||||||
|
"pos.nevybrane_nic_na_platbu": "Nie su vybrané žiadné položky na platbu.",
|
||||||
|
"pos.vybrane_polozky_sa_nedaju_platit": "Vybrané položky sa nedajú pripraviť na platbu.",
|
||||||
|
"pos.chyba_cenika": "Price list error",
|
||||||
|
"pos.polozkanema_ziadnu_cenu": "Položka nemá žiadnu cenovú hladinu.\nNedá sa nablokovať.",
|
||||||
|
"pos.nedostupna_pre_hladinu": "Hladina {level} nie je pre túto položku dostupná.\nPoužije sa prvá dostupná cena.",
|
||||||
|
"pos.selected": "Selected",
|
||||||
|
|
||||||
|
"payment.title": "Payment",
|
||||||
|
"payment.step_discount": "Discount / card",
|
||||||
|
"payment.step_payments": "Payments",
|
||||||
|
"payment.amount_due": "Amount due",
|
||||||
|
"payment.total": "Total",
|
||||||
|
"payment.discount": "Discount",
|
||||||
|
"payment.after_discount": "After discount",
|
||||||
|
"payment.paid": "Paid",
|
||||||
|
"payment.remaining": "Remaining",
|
||||||
|
"payment.printer": "Print",
|
||||||
|
"payment.copies": "Copies",
|
||||||
|
"payment.no_payment_selected": "No payment was selected.",
|
||||||
|
"receipt.title": "Receipt",
|
||||||
|
"receipt.copy": "Receipt copy",
|
||||||
|
"receipt.storno": "Receipt void",
|
||||||
|
"receipt.payment_change": "Payment type change",
|
||||||
|
"closed_receipts.title": "Receipts",
|
||||||
|
"closed_receipts.current": "Current receipts",
|
||||||
|
"closed_receipts.date": "Date",
|
||||||
|
"closed_receipts.print_copy": "Print receipt copy",
|
||||||
|
"closed_receipts.change_payment": "Change payments",
|
||||||
|
"closed_receipts.enter_tip": "Enter TIP",
|
||||||
|
"limit.full_payment_only": "A limit table can only be paid in full.",
|
||||||
|
"limit.transfer_mapping": "Limit table mapping",
|
||||||
|
"limit.courses": "Courses",
|
||||||
|
"limit.guests": "Guests / price levels",
|
||||||
|
"error.title": "Error",
|
||||||
|
"error.server": "Server error",
|
||||||
|
"common.empty": "Empty",
|
||||||
|
"common.none": "None",
|
||||||
|
"common.yes": "Yes",
|
||||||
|
"common.no": "No"
|
||||||
|
}
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
{
|
||||||
|
"app.name": "Pokladňa",
|
||||||
|
"button.ok": "OK",
|
||||||
|
"button.cancel": "Zrušiť",
|
||||||
|
"button.back": "Späť",
|
||||||
|
"button.close": "Zavrieť",
|
||||||
|
"button.pay": "Platba",
|
||||||
|
"button.pay_selected": "Platba\nvybraného",
|
||||||
|
"button.save": "Uložiť",
|
||||||
|
"button.search": "Hľadať",
|
||||||
|
"button.code": "Kódom",
|
||||||
|
"button.loyalty_card": "Vernostná karta",
|
||||||
|
"button.print": "Tlač",
|
||||||
|
"button.printer": "Tlačiareň",
|
||||||
|
"button.execute_payment": "Vykonať platbu",
|
||||||
|
"button.receipt_preview": "Predúčet",
|
||||||
|
"button.send_email": "Poslať e-mailom",
|
||||||
|
"button.tip": "TIP",
|
||||||
|
"button.delete": "Zmazať",
|
||||||
|
"button.storno": "Storno",
|
||||||
|
"login.title": "Prihlásenie",
|
||||||
|
"login.password": "Heslo",
|
||||||
|
"login.invalid": "Neplatné prihlásenie",
|
||||||
|
"account.bar": "Bar",
|
||||||
|
"account.open_tables": "Otvorené stoly",
|
||||||
|
"account.closed_receipts": "Účty",
|
||||||
|
"account.limits": "Limity",
|
||||||
|
"pos.action_panel": "Akcie",
|
||||||
|
"pos.payment": "Platba",
|
||||||
|
"pos.item_storno": "Storno položky",
|
||||||
|
"pos.transfer_table": "Presun na stôl",
|
||||||
|
"pos.message_for_item": "Správa pre položku",
|
||||||
|
"pos.vsetci": "Všetci",
|
||||||
|
"pos.price_level": "Cenová hladina",
|
||||||
|
"pos.guest": "Hosť",
|
||||||
|
"pos.course": "Chod",
|
||||||
|
"pos.table": "Stôl",
|
||||||
|
"pos.add": "Pridať",
|
||||||
|
"pos.prevod": "Prevod",
|
||||||
|
"pos.prevod_bez_poloziek": "Nie su vybrané žiadne položky na prevod.",
|
||||||
|
"pos.uver_hlavicka": "Úverový záznam - výber firmy",
|
||||||
|
"pos.uver_hint": "Hľadať firmu, adresu, IČO, DIČ...",
|
||||||
|
"pos.uver_nova_firma": "Nová firma",
|
||||||
|
"pos.uver_nenajdena_firma": "Žiadna firma nevyhovuje hľadaniu.",
|
||||||
|
"pos.uverovy_zaznam": "Úverový záznam",
|
||||||
|
"pos.uver_firma": "Firma",
|
||||||
|
"pos.uver_adresa": "Adresa",
|
||||||
|
"pos.uver_ico": "IČO",
|
||||||
|
"pos.uver_icdph": "IČ DPH",
|
||||||
|
"pos.uver_dic": "DIČ",
|
||||||
|
"pos.uver_akcia": "Akcia",
|
||||||
|
"pos.uver_schvalil": "Schválil",
|
||||||
|
"pos.uver_povinne_meno": "Meno firmy je povinné.",
|
||||||
|
"pos.uver_povinne_schvalil": "Meno schvalovateľa je povinné.",
|
||||||
|
"pos.uver_povinne_meno": "Meno firmy je povinné.",
|
||||||
|
"pos.recepcia_vyber": "Výber recepcie",
|
||||||
|
"pos.recepcia_hladanie": "Hľadať recepciu ...",
|
||||||
|
"pos.recepcia_nenastavene": "Nie je nastavená žiadna recepcia",
|
||||||
|
"pos.recepcia_prefix": "Prefix",
|
||||||
|
"pos.recepcia_typ": "Typ",
|
||||||
|
"pos.recepcia_izba_skupina": "izba/skupina",
|
||||||
|
"pos.recepcia_hint": "Hľadať izbu, skupinu alebo hosťa...",
|
||||||
|
"pos.recepcia_cislo_izby": "Číslo izby",
|
||||||
|
"pos.recepcia_overit_izbu": "Overiť izbu",
|
||||||
|
"pos.recepcia_karta": "Karta",
|
||||||
|
"pos.recepcia_ziadne_izby": "Žiadne izby na výber.",
|
||||||
|
"pos.recepcia": "Recepcia",
|
||||||
|
"pos.recepcia_no_charge":"Na túto izbu nie je možné naťažovať.",
|
||||||
|
"pos.recepcia_hladanie_hosta": "Hľadanie hosťa...",
|
||||||
|
"pos.recepcia_vyber_hosta": "Výber hosťa...",
|
||||||
|
"pos.recepcia_ziadny_host": "Žiadny hosť.",
|
||||||
|
"pos.hladat_polozku": "Hľadať položku...",
|
||||||
|
"pos.meno_hosta": "Meno hosťa",
|
||||||
|
"pos.nazov_chodu": "Názov chodu",
|
||||||
|
"pos.sprava_pre": "Správa pre",
|
||||||
|
"pos.zadat_spravu": "Zadať správu",
|
||||||
|
"pos.sprava_povinna_musis_vybrat": "Musíte vybrať povinnú správu",
|
||||||
|
"pos.kasa": "Kasa",
|
||||||
|
"pos.terminal": "Terminál",
|
||||||
|
"pos.neplatna_cen_hladina": "Neplatná cenová hladina v nastavení zľavy.",
|
||||||
|
"pos.zlava": "zľava",
|
||||||
|
"pos.hladina_id": "hladina id",
|
||||||
|
"pos.neplatny_param_zlavy_dotaz_st": "Neplatný parameter zľavy pre dotaz_st.",
|
||||||
|
"pos.nenacitane_firmy": "Firmy pre úverový záznam sa nepodarilo načítať",
|
||||||
|
"pos.neulozena_firma": "Firmu sa nepodarilo uložiť",
|
||||||
|
"pos.recepcia_nenacitane": "Recepcie sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_izby_nenacitane": "Izby sa nepodarilo načítať",
|
||||||
|
"pos.recepcia_nacitanie_karty": "Nacitanie hotelovej karty",
|
||||||
|
"pos.recepcia_cislo_karty": "Číslo karty",
|
||||||
|
"pos.recepcia_neoverena_karta": "Hotelovú kartu sa nepodarilo overiť",
|
||||||
|
"pos.recepcia_nenacitani_hostia": "Nepodarilo sa načítať hostí z izby",
|
||||||
|
"pos.recepcia_ziaden_host": "Na izbe sa nenašiel žiadny hosť.",
|
||||||
|
"pos.nie_je_co_platit": "Nie je čo platiť.",
|
||||||
|
"pos.def_cen_hlad": "Východzia cenová hladina",
|
||||||
|
"pos_polozka_xy_nie_je_v_cenniku": "Položka s kódem {code} nebyla nalezena v ceníku.",
|
||||||
|
"pos.kod_nenajdeny": "Kód nenájdený",
|
||||||
|
"pos.naozaj_zrusit_editaciu_uctu": "Naozaj chcete zrušiť editáciu účtu?",
|
||||||
|
"pos.neulozene_zmenu_sa_stratia": "Neuložené zmeny sa stratia",
|
||||||
|
"button.ano": "Áno",
|
||||||
|
"button.nie": "Nie",
|
||||||
|
"pos.zrusit_editaciu": "Zrušiť editáciu",
|
||||||
|
"pos.vyber_spravu_pre": "Vyber správu pre",
|
||||||
|
"pos.povinne_cislo_faktury": "Musíte zadať číslo faktúry",
|
||||||
|
"pos.pohladavka_musi_byt_sama": "Pohľadávku nie je možné kombinovať s inými položkami na jednom účte.",
|
||||||
|
"pos.uhrada_pohladavky": "Úhrada pohľadávky",
|
||||||
|
"pos.prazdny_ucet": "Účet je prázdny.",
|
||||||
|
"pos.nie_je_co_stornovat": "Nie je čostornovať",
|
||||||
|
"pos.nic_nevybrane_na_storno": "Nie su vybrané žiadné položky na storno.",
|
||||||
|
"pos.limit_iba_cely": "Limitový stôl sa dá zaplatiť iba celý naraz.",
|
||||||
|
"pos.nevybrane_nic_na_platbu": "Nie su vybrané žiadné položky na platbu.",
|
||||||
|
"pos.vybrane_polozky_sa_nedaju_platit": "Vybrané položky sa nedajú pripraviť na platbu.",
|
||||||
|
"pos.chyba_cenika": "Chyba cenníka",
|
||||||
|
"pos.polozkanema_ziadnu_cenu": "Položka nemá žiadnu cenovú hladinu.\nNedá sa nablokovať.",
|
||||||
|
"pos.nedostupna_pre_hladinu": "Hladina {level} nie je pre túto položku dostupná.\nPoužije sa prvá dostupná cena.",
|
||||||
|
"pos.selected": "Vybrané",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"payment.title": "Platba",
|
||||||
|
"payment.step_discount": "Zľava / karta",
|
||||||
|
"payment.step_payments": "Platby",
|
||||||
|
"payment.amount_due": "K úhrade",
|
||||||
|
"payment.total": "Celková suma",
|
||||||
|
"payment.discount": "Zľava",
|
||||||
|
"payment.after_discount": "Suma po zľave",
|
||||||
|
"payment.paid": "Zaplatené",
|
||||||
|
"payment.remaining": "Zostáva",
|
||||||
|
"payment.printer": "Tlač",
|
||||||
|
"payment.copies": "Kópií",
|
||||||
|
"payment.no_payment_selected": "Nebola vybraná žiadna platba.",
|
||||||
|
"receipt.title": "Účet",
|
||||||
|
"receipt.copy": "Kópia účtu",
|
||||||
|
"receipt.storno": "Storno účtu",
|
||||||
|
"receipt.payment_change": "Zmena druhu platby",
|
||||||
|
"closed_receipts.title": "Účty",
|
||||||
|
"closed_receipts.current": "Aktuálne účty",
|
||||||
|
"closed_receipts.date": "Dátum",
|
||||||
|
"closed_receipts.print_copy": "Tlač kópie účtu",
|
||||||
|
"closed_receipts.change_payment": "Zmeniť platby",
|
||||||
|
"closed_receipts.enter_tip": "Zadanie TIPu",
|
||||||
|
"limit.full_payment_only": "Limitový stôl sa dá zaplatiť iba celý naraz.",
|
||||||
|
"limit.transfer_mapping": "Priradenie na limitový stôl",
|
||||||
|
"limit.courses": "Chody",
|
||||||
|
"limit.guests": "Hostia / hladiny",
|
||||||
|
"error.title": "Chyba",
|
||||||
|
"error.server": "Chyba servera",
|
||||||
|
"common.empty": "Prázdne",
|
||||||
|
"common.none": "Žiadne",
|
||||||
|
"common.yes": "Áno",
|
||||||
|
"common.no": "Nie"
|
||||||
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.clock import Clock
|
||||||
|
|
||||||
|
from ui_utils import _popup_info
|
||||||
|
import numberpad
|
||||||
|
from kivy.uix.anchorlayout import AnchorLayout
|
||||||
|
from kivy.core.window import Window
|
||||||
|
|
||||||
|
MAX_LOGIN_FAILS = 3 # nebo treba 5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LoginUserScreen(Screen):
|
||||||
|
def __init__(self, controller, on_success, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.fail_count = 0
|
||||||
|
self.controller = controller
|
||||||
|
self.on_success = on_success
|
||||||
|
root = BoxLayout(orientation="vertical")
|
||||||
|
self.lbl_info = Label(
|
||||||
|
text="Zadej PIN číšníka",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=40,
|
||||||
|
)
|
||||||
|
self.lbl_error = Label(
|
||||||
|
text="",
|
||||||
|
color=(1, 0, 0, 1),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=30,
|
||||||
|
)
|
||||||
|
root.add_widget(self.lbl_info)
|
||||||
|
root.add_widget(self.lbl_error)
|
||||||
|
self.center_layout = AnchorLayout(anchor_x="center", anchor_y="center")
|
||||||
|
root.add_widget(self.center_layout)
|
||||||
|
self.pad = None
|
||||||
|
self._keyboard_bound = False
|
||||||
|
self.add_widget(root)
|
||||||
|
|
||||||
|
def _on_key_down(self, window, key, scancode, codepoint, modifiers):
|
||||||
|
if self.manager and self.manager.current != self.name:
|
||||||
|
return False
|
||||||
|
if self.pad:
|
||||||
|
if key == 27:
|
||||||
|
self.pad._cancel()
|
||||||
|
return True # 🔥 zabráni zatvoreniu appky
|
||||||
|
if key in range(48, 58): # top row
|
||||||
|
self.pad._press(chr(key))
|
||||||
|
return True
|
||||||
|
elif key in range(256, 266): # numpad
|
||||||
|
self.pad._press(str(key - 256))
|
||||||
|
return True
|
||||||
|
elif chr(key)=='*' or key == 268:
|
||||||
|
self.pad._press("*")
|
||||||
|
return True
|
||||||
|
elif chr(key)=='.' or key == 266:
|
||||||
|
self.pad._press(".")
|
||||||
|
return True
|
||||||
|
elif key > 300:
|
||||||
|
print("pass")
|
||||||
|
pass
|
||||||
|
return True
|
||||||
|
elif codepoint and (codepoint.isalpha() or codepoint.isdigit()):
|
||||||
|
self.pad._press(codepoint)
|
||||||
|
return True
|
||||||
|
elif key == 8:
|
||||||
|
self.pad._press('⌫')
|
||||||
|
return True
|
||||||
|
elif key in (13, 40, 10, 271): # Enter / Numpad Enter
|
||||||
|
self.pad._accept()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_enter(self):
|
||||||
|
self._bind_keyboard()
|
||||||
|
self.lbl_error.text = ""
|
||||||
|
if self.pad:
|
||||||
|
self.center_layout.remove_widget(self.pad)
|
||||||
|
self.pad = numberpad.NumberPad(
|
||||||
|
mode="code",
|
||||||
|
max_len=10,
|
||||||
|
on_accept=self._accept,
|
||||||
|
on_cancel=self._cancel,
|
||||||
|
)
|
||||||
|
self.pad.size_hint = (None, None)
|
||||||
|
self.pad.size = (dp(300), dp(400))
|
||||||
|
self.center_layout.add_widget(self.pad)
|
||||||
|
|
||||||
|
def on_leave(self):
|
||||||
|
self._unbind_keyboard()
|
||||||
|
if self.pad:
|
||||||
|
self.center_layout.remove_widget(self.pad)
|
||||||
|
self.pad = None
|
||||||
|
|
||||||
|
def _bind_keyboard(self):
|
||||||
|
if self._keyboard_bound:
|
||||||
|
return
|
||||||
|
Window.unbind(on_key_down=self._on_key_down)
|
||||||
|
Window.bind(on_key_down=self._on_key_down)
|
||||||
|
self._keyboard_bound = True
|
||||||
|
|
||||||
|
def _unbind_keyboard(self):
|
||||||
|
Window.unbind(on_key_down=self._on_key_down)
|
||||||
|
self._keyboard_bound = False
|
||||||
|
|
||||||
|
def _accept(self, pin: str):
|
||||||
|
try:
|
||||||
|
self.controller.login_user(pin)
|
||||||
|
# úspěch → reset čítače
|
||||||
|
self.fail_count = 0
|
||||||
|
Logger.info("LOGIN USER OK")
|
||||||
|
self.on_success()
|
||||||
|
except Exception as e:
|
||||||
|
self.fail_count += 1
|
||||||
|
Logger.warning(
|
||||||
|
f"LOGIN FAILED ({self.fail_count}): {type(e).__name__}: {e}"
|
||||||
|
)
|
||||||
|
self.pad.clear()
|
||||||
|
# příliš mnoho pokusů → konec aplikace
|
||||||
|
if self.fail_count >= MAX_LOGIN_FAILS:
|
||||||
|
Logger.error("MAX LOGIN FAILS REACHED")
|
||||||
|
_popup_info("Chyba", "Příliš mnoho chybných pokusů.\nAplikace bude ukončena.")
|
||||||
|
Clock.schedule_once(lambda *_: App.get_running_app().stop(), 2)
|
||||||
|
|
||||||
|
def _cancel(self):
|
||||||
|
# v POS obvykle znamená ukončení aplikace
|
||||||
|
Logger.info("LOGIN CANCEL")
|
||||||
|
App.get_running_app().stop()
|
||||||
+1575
File diff suppressed because it is too large
Load Diff
+10481
File diff suppressed because it is too large
Load Diff
+730
@@ -0,0 +1,730 @@
|
|||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.graphics import Color, RoundedRectangle
|
||||||
|
from kivy.uix.widget import Widget
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.floatlayout import FloatLayout
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
from kivy.metrics import dp, Metrics
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.screenmanager import Screen
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from ui_utils import ucet_ui_type, UCET_COLORS
|
||||||
|
from kivy.uix.textinput import TextInput
|
||||||
|
from kivy.uix.popup import Popup
|
||||||
|
from ui_utils import _popup_info
|
||||||
|
import time
|
||||||
|
import data
|
||||||
|
MAP_H = 900
|
||||||
|
MAP_W = 1400
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# TABLE WIDGET (jede nad data.Table)
|
||||||
|
# =====================================================
|
||||||
|
class TableWidget(Widget):
|
||||||
|
def __init__(self, table: data.Table, state=None, on_press=None, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.table = table
|
||||||
|
self.state = state
|
||||||
|
self.on_press = on_press
|
||||||
|
self.edit_mode = False
|
||||||
|
self.dragging = False
|
||||||
|
self._last_touch_time = 0
|
||||||
|
with self.canvas.before:
|
||||||
|
self.color = Color(1, 1, 1, 1)
|
||||||
|
self.rect = RoundedRectangle(
|
||||||
|
pos=self.pos,
|
||||||
|
size=self.size,
|
||||||
|
radius=[(0, 0)] * 4
|
||||||
|
)
|
||||||
|
self.label = Label(
|
||||||
|
text="",
|
||||||
|
color=(1, 1, 1, 1),
|
||||||
|
halign="center",
|
||||||
|
valign="middle",
|
||||||
|
font_size=dp(16),
|
||||||
|
)
|
||||||
|
self.add_widget(self.label)
|
||||||
|
self.bind(pos=self._update, size=self._update)
|
||||||
|
self._update_color()
|
||||||
|
self._update_text()
|
||||||
|
# ---------------- COLOR ----------------
|
||||||
|
def _update_color(self):
|
||||||
|
u = self.state
|
||||||
|
if not u:
|
||||||
|
self.color.rgba = UCET_COLORS["normal"]
|
||||||
|
return
|
||||||
|
ui_type = ucet_ui_type(u)
|
||||||
|
self.color.rgba = UCET_COLORS.get(ui_type, UCET_COLORS["open"])
|
||||||
|
# ---------------- TEXT ----------------
|
||||||
|
def _update_text(self):
|
||||||
|
u = self.state
|
||||||
|
txt = f"{self.table.name}\n[{self.table.id}]"
|
||||||
|
if u:
|
||||||
|
if u.blocked_by:
|
||||||
|
txt += "\nBLOK"
|
||||||
|
elif not u.closed_at:
|
||||||
|
txt += "\nOBSAZENO"
|
||||||
|
self.label.text = txt
|
||||||
|
# ---------------- DRAW ----------------
|
||||||
|
def _update(self, *args):
|
||||||
|
self.rect.pos = self.pos
|
||||||
|
self.rect.size = self.size
|
||||||
|
r = min(self.width, self.height) * self.table.radius
|
||||||
|
self.rect.radius = [r, r, r, r]
|
||||||
|
self.label.pos = self.pos
|
||||||
|
self.label.size = self.size
|
||||||
|
self.label.text_size = self.size
|
||||||
|
# ---------------- CLICK ----------------
|
||||||
|
def on_touch_down(self, touch):
|
||||||
|
if not self.collide_point(*touch.pos):
|
||||||
|
return super().on_touch_down(touch)
|
||||||
|
# ===== POKLADNA =====
|
||||||
|
if not self.edit_mode:
|
||||||
|
if self.on_press:
|
||||||
|
self.on_press(self.table.id)
|
||||||
|
return True
|
||||||
|
# ===== EDITOR =====
|
||||||
|
now = time.time()
|
||||||
|
# double tap → edit
|
||||||
|
if now - self._last_touch_time < 0.3:
|
||||||
|
self.dragging = False
|
||||||
|
self.open_edit_popup()
|
||||||
|
return True
|
||||||
|
self._last_touch_time = now
|
||||||
|
self.dragging = True
|
||||||
|
return True
|
||||||
|
def on_touch_move(self, touch):
|
||||||
|
if self.edit_mode and self.dragging:
|
||||||
|
parent = self.parent
|
||||||
|
if not parent:
|
||||||
|
return True
|
||||||
|
new_x = touch.x - self.width / 2
|
||||||
|
new_y = touch.y - self.height / 2
|
||||||
|
# clamp
|
||||||
|
new_x = max(0, min(new_x, parent.width - self.width))
|
||||||
|
new_y = max(0, min(new_y, parent.height - self.height))
|
||||||
|
self.pos = (new_x, new_y)
|
||||||
|
self.table.pos_x = int(new_x / Metrics.density)
|
||||||
|
self.table.pos_y = int(new_y / Metrics.density)
|
||||||
|
return True
|
||||||
|
return super().on_touch_move(touch)
|
||||||
|
def on_touch_up(self, touch):
|
||||||
|
if self.dragging:
|
||||||
|
grid = dp(20)
|
||||||
|
self.table.pos_x = int((self.table.pos_x // grid) * grid)
|
||||||
|
self.table.pos_y = int((self.table.pos_y // grid) * grid)
|
||||||
|
self.dragging = False
|
||||||
|
return super().on_touch_up(touch)
|
||||||
|
def _check_id_duplicate(self, instance, value):
|
||||||
|
new_id = value.strip()
|
||||||
|
if not new_id:
|
||||||
|
instance.background_color = (1, 1, 1, 1)
|
||||||
|
return
|
||||||
|
old_id = str(self.table.id).strip()
|
||||||
|
duplicate = False
|
||||||
|
rooms_with_id = []
|
||||||
|
try:
|
||||||
|
provider = self.parent.parent.parent.provider
|
||||||
|
rooms = provider.get_rooms() if provider else []
|
||||||
|
except Exception:
|
||||||
|
rooms = []
|
||||||
|
for room in rooms:
|
||||||
|
room_name = getattr(room, "room_name", "Room")
|
||||||
|
for t in getattr(room, "stoly", []):
|
||||||
|
if str(t.id).strip() == new_id and new_id != old_id:
|
||||||
|
duplicate = True
|
||||||
|
rooms_with_id.append(room_name)
|
||||||
|
break
|
||||||
|
if duplicate:
|
||||||
|
instance.background_color = (1, 0.3, 0.3, 1)
|
||||||
|
_popup_info("Duplicitní ID",f"ID existuje v: {', '.join(rooms_with_id)}")
|
||||||
|
else:
|
||||||
|
instance.background_color = (1, 1, 1, 1)
|
||||||
|
def open_edit_popup(self):
|
||||||
|
from kivy.uix.scrollview import ScrollView
|
||||||
|
# ================= ROOT =================
|
||||||
|
root = BoxLayout(orientation="vertical", spacing=dp(5), padding=dp(5))
|
||||||
|
scroll = ScrollView(size_hint=(1, 1))
|
||||||
|
content = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(5),
|
||||||
|
size_hint_y=None
|
||||||
|
)
|
||||||
|
content.bind(minimum_height=content.setter("height"))
|
||||||
|
scroll.add_widget(content)
|
||||||
|
root.add_widget(scroll)
|
||||||
|
# ================= INPUTY =================
|
||||||
|
id_in = TextInput(text=str(self.table.id), multiline=False)
|
||||||
|
id_in.bind(text=self._check_id_duplicate)
|
||||||
|
name_in = TextInput(text=self.table.name, multiline=False)
|
||||||
|
x_in = TextInput(text=str(self.table.pos_x), multiline=False)
|
||||||
|
y_in = TextInput(text=str(self.table.pos_y), multiline=False)
|
||||||
|
w_in = TextInput(text=str(self.table.width), multiline=False)
|
||||||
|
h_in = TextInput(text=str(self.table.height), multiline=False)
|
||||||
|
r_in = TextInput(text=str(self.table.radius), multiline=False)
|
||||||
|
def row(label, widget):
|
||||||
|
r = BoxLayout(size_hint_y=None, height=dp(50))
|
||||||
|
r.add_widget(Label(text=label, size_hint_x=0.4))
|
||||||
|
r.add_widget(widget)
|
||||||
|
return r
|
||||||
|
content.add_widget(row("ID", id_in))
|
||||||
|
content.add_widget(row("Název", name_in))
|
||||||
|
content.add_widget(row("X", x_in))
|
||||||
|
content.add_widget(row("Y", y_in))
|
||||||
|
content.add_widget(row("Šířka", w_in))
|
||||||
|
content.add_widget(row("Výška", h_in))
|
||||||
|
content.add_widget(row("Radius", r_in))
|
||||||
|
# ================= POPUP =================
|
||||||
|
popup = Popup(
|
||||||
|
title="Edit stolu",
|
||||||
|
content=root,
|
||||||
|
size_hint=(0.6, 0.85),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
# ================= HELPERS =================
|
||||||
|
def _num(txt, default=0):
|
||||||
|
txt = (txt or "").strip().replace(",", ".")
|
||||||
|
if not txt:
|
||||||
|
return default
|
||||||
|
return float(txt)
|
||||||
|
# ================= SAVE =================
|
||||||
|
def save(_):
|
||||||
|
try:
|
||||||
|
self.table.id = id_in.text.strip()
|
||||||
|
self.table.name = name_in.text.strip()
|
||||||
|
self.table.pos_x = int(_num(x_in.text))
|
||||||
|
self.table.pos_y = int(_num(y_in.text))
|
||||||
|
self.table.width = int(_num(w_in.text))
|
||||||
|
self.table.height = int(_num(h_in.text))
|
||||||
|
self.table.radius = _num(r_in.text)
|
||||||
|
self.pos = (
|
||||||
|
dp(self.table.pos_x),
|
||||||
|
dp(self.table.pos_y),
|
||||||
|
)
|
||||||
|
self.size = (
|
||||||
|
dp(self.table.width),
|
||||||
|
dp(self.table.height),
|
||||||
|
)
|
||||||
|
self.dragging = False
|
||||||
|
self._update_text()
|
||||||
|
self._update()
|
||||||
|
popup.dismiss()
|
||||||
|
except Exception as e:
|
||||||
|
print("Chyba při ukládání:", e)
|
||||||
|
# ================= DELETE =================
|
||||||
|
def delete_table(_):
|
||||||
|
confirm_layout = BoxLayout(orientation="vertical", spacing=10, padding=10)
|
||||||
|
confirm_layout.add_widget(Label(
|
||||||
|
text=f"Opravdu smazat stůl?\n\n{self.table.name}",
|
||||||
|
halign="center"
|
||||||
|
))
|
||||||
|
btn_yes = Button(text="ANO smazat")
|
||||||
|
btn_no = Button(text="Ne")
|
||||||
|
confirm_layout.add_widget(btn_yes)
|
||||||
|
confirm_layout.add_widget(btn_no)
|
||||||
|
confirm_popup = Popup(
|
||||||
|
title="Smazání stolu",
|
||||||
|
content=confirm_layout,
|
||||||
|
size_hint=(0.5, 0.4),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
def do_delete(_):
|
||||||
|
if self.parent:
|
||||||
|
self.parent.remove_widget(self)
|
||||||
|
confirm_popup.dismiss()
|
||||||
|
popup.dismiss()
|
||||||
|
btn_yes.bind(on_press=do_delete)
|
||||||
|
btn_no.bind(on_press=lambda *_: confirm_popup.dismiss())
|
||||||
|
confirm_popup.open()
|
||||||
|
# ================= BUTTONY =================
|
||||||
|
btn_save = Button(text="Uložit", size_hint_y=None, height=dp(50))
|
||||||
|
btn_cancel = Button(
|
||||||
|
text="Zrušit",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(50),
|
||||||
|
background_color=(0.6, 0.6, 0.6, 1),
|
||||||
|
)
|
||||||
|
btn_delete = Button(
|
||||||
|
text="Smazat stůl",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(50),
|
||||||
|
background_color=(0.8, 0.2, 0.2, 1),
|
||||||
|
)
|
||||||
|
btn_row = BoxLayout(
|
||||||
|
orientation="horizontal",
|
||||||
|
spacing=dp(5),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(50),
|
||||||
|
)
|
||||||
|
btn_row.add_widget(btn_save)
|
||||||
|
btn_row.add_widget(btn_cancel)
|
||||||
|
btn_row.add_widget(btn_delete)
|
||||||
|
root.add_widget(btn_row)
|
||||||
|
# ================= BINDY =================
|
||||||
|
btn_save.bind(on_press=save)
|
||||||
|
btn_delete.bind(on_press=delete_table)
|
||||||
|
btn_cancel.bind(on_press=lambda *_: popup.dismiss())
|
||||||
|
popup.bind(on_dismiss=lambda *_: setattr(self, "dragging", False))
|
||||||
|
popup.open()
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# PROVIDER (vrací data.Room přímo)
|
||||||
|
# =====================================================
|
||||||
|
class RoomMapProvider:
|
||||||
|
def __init__(self, controller=None):
|
||||||
|
self.controller = controller
|
||||||
|
self.current_room = None
|
||||||
|
|
||||||
|
def set_current_room(self, room_name):
|
||||||
|
self.current_room = room_name
|
||||||
|
def get_table_states(self):
|
||||||
|
if not self.controller:
|
||||||
|
return {}
|
||||||
|
ucty = self.controller.load_stoly(closed=False) or []
|
||||||
|
return {str(u.stul): u for u in ucty}
|
||||||
|
def get_rooms(self):
|
||||||
|
if not self.controller or not self.controller.mapa_stolu:
|
||||||
|
return []
|
||||||
|
rooms_out = []
|
||||||
|
for r in self.controller.mapa_stolu.rooms:
|
||||||
|
# ---------------- ROOM ----------------
|
||||||
|
if isinstance(r, dict):
|
||||||
|
room_name = r.get("room_name")
|
||||||
|
raw_tables = r.get("stoly", [])
|
||||||
|
else:
|
||||||
|
room_name = getattr(r, "room_name", None)
|
||||||
|
raw_tables = getattr(r, "stoly", [])
|
||||||
|
tables = []
|
||||||
|
# ---------------- TABLES ----------------
|
||||||
|
for t in raw_tables:
|
||||||
|
if isinstance(t, dict):
|
||||||
|
tables.append(data.Table(
|
||||||
|
id=t.get("id"),
|
||||||
|
name=t.get("name"),
|
||||||
|
pos_x=t.get("pos_x", 0),
|
||||||
|
pos_y=t.get("pos_y", 0),
|
||||||
|
width=t.get("width", 100),
|
||||||
|
height=t.get("height", 100),
|
||||||
|
radius=t.get("radius", 0.0),
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
# už je to data.Table → použij rovnou
|
||||||
|
tables.append(t)
|
||||||
|
rooms_out.append(data.Room(
|
||||||
|
room_name=room_name,
|
||||||
|
stoly=tables
|
||||||
|
))
|
||||||
|
limit_room = self._limit_room()
|
||||||
|
if limit_room:
|
||||||
|
rooms_out.append(limit_room)
|
||||||
|
return rooms_out
|
||||||
|
|
||||||
|
def _limit_room(self):
|
||||||
|
if not self.controller:
|
||||||
|
return None
|
||||||
|
if hasattr(self.controller, "limits_room_enabled") and not self.controller.limits_room_enabled():
|
||||||
|
return None
|
||||||
|
active = str(self.current_room or "").strip().lower() == "limity"
|
||||||
|
if active and hasattr(self.controller, "load_limit_tables"):
|
||||||
|
limits = self.controller.load_limit_tables(force=True) or []
|
||||||
|
elif hasattr(self.controller, "cached_limit_tables"):
|
||||||
|
limits = self.controller.cached_limit_tables() or []
|
||||||
|
else:
|
||||||
|
limits = []
|
||||||
|
if active:
|
||||||
|
Logger.info(f"RoomMapProvider: refreshing Limity room with {len(limits)} tables")
|
||||||
|
cols = 4
|
||||||
|
w = 260
|
||||||
|
h = 110
|
||||||
|
sp_x = 24
|
||||||
|
sp_y = 22
|
||||||
|
start_x = 30
|
||||||
|
start_y = 760
|
||||||
|
tables = []
|
||||||
|
for idx, item in enumerate(limits):
|
||||||
|
col = idx % cols
|
||||||
|
row = idx // cols
|
||||||
|
tables.append(data.Table(
|
||||||
|
id=item.table_id,
|
||||||
|
name=item.name or item.menolimit or item.table_id,
|
||||||
|
pos_x=start_x + col * (w + sp_x),
|
||||||
|
pos_y=max(20, start_y - row * (h + sp_y)),
|
||||||
|
width=w,
|
||||||
|
height=h,
|
||||||
|
radius=0.05,
|
||||||
|
))
|
||||||
|
return data.Room(room_name="Limity", stoly=tables)
|
||||||
|
|
||||||
|
def _fallback_rooms(self):
|
||||||
|
return [
|
||||||
|
data.Room(
|
||||||
|
room_name="Test, mapa neexistuje",
|
||||||
|
stoly=[
|
||||||
|
data.Table(
|
||||||
|
id="1",
|
||||||
|
name="VIP",
|
||||||
|
pos_x=150,
|
||||||
|
pos_y=500,
|
||||||
|
width=100,
|
||||||
|
height=100,
|
||||||
|
radius=1.0,
|
||||||
|
),
|
||||||
|
data.Table(
|
||||||
|
id="2",
|
||||||
|
name="Bar",
|
||||||
|
pos_x=380,
|
||||||
|
pos_y=420,
|
||||||
|
width=100,
|
||||||
|
height=100,
|
||||||
|
radius=0.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MAP WIDGET
|
||||||
|
# =====================================================
|
||||||
|
class RoomTableMapWidget(BoxLayout):
|
||||||
|
def __init__(self, *, provider, on_select, **kwargs):
|
||||||
|
super().__init__(orientation="vertical", **kwargs)
|
||||||
|
|
||||||
|
self.provider = provider
|
||||||
|
self.on_select = on_select
|
||||||
|
self.current_room = None
|
||||||
|
|
||||||
|
self.scroll = ScrollView(
|
||||||
|
size_hint=(1, 1),
|
||||||
|
do_scroll_x=True,
|
||||||
|
do_scroll_y=True,
|
||||||
|
bar_width=dp(10),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.map_area = FloatLayout(
|
||||||
|
size_hint=(None, None),
|
||||||
|
size=(dp(MAP_W), dp(MAP_H)),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.scroll.add_widget(self.map_area)
|
||||||
|
self.add_widget(self.scroll)
|
||||||
|
|
||||||
|
# ---------------- REFRESH ----------------
|
||||||
|
def refresh(self):
|
||||||
|
self.map_area.clear_widgets()
|
||||||
|
if hasattr(self.provider, "set_current_room"):
|
||||||
|
self.provider.set_current_room(self.current_room)
|
||||||
|
rooms = self.provider.get_rooms()
|
||||||
|
states = self.provider.get_table_states() if hasattr(self.provider, "get_table_states") else {}
|
||||||
|
if not self.current_room and rooms:
|
||||||
|
self.current_room = self._get_room_name(rooms[0])
|
||||||
|
room = next((r for r in rooms if self._get_room_name(r) == self.current_room), None)
|
||||||
|
if not room:
|
||||||
|
return
|
||||||
|
for t in room.stoly:
|
||||||
|
u = None if getattr(self, "edit_mode", False) else states.get(str(t.id))
|
||||||
|
widget = TableWidget(
|
||||||
|
t,
|
||||||
|
state=u,
|
||||||
|
on_press=self._select,
|
||||||
|
)
|
||||||
|
widget.edit_mode = getattr(self, "edit_mode", False)
|
||||||
|
widget.size_hint = (None, None)
|
||||||
|
widget.size = (dp(t.width), dp(t.height))
|
||||||
|
widget.pos = (
|
||||||
|
dp(t.pos_x),
|
||||||
|
dp(t.pos_y)
|
||||||
|
)
|
||||||
|
self.map_area.add_widget(widget)
|
||||||
|
# ---------------- HELPERS ----------------
|
||||||
|
def _get_room_name(self, room):
|
||||||
|
return getattr(room, "room_name", None) or getattr(room, "name", "Room")
|
||||||
|
|
||||||
|
# ---------------- SELECT ----------------
|
||||||
|
def _select(self, table_id):
|
||||||
|
if self.on_select:
|
||||||
|
self.on_select(table_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MapaEditor(Screen):
|
||||||
|
def __init__(self, controller, back_screen, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.controller = controller
|
||||||
|
self.back_screen = back_screen
|
||||||
|
# ===== ROOT =====
|
||||||
|
root = BoxLayout(orientation="vertical")
|
||||||
|
# ===== MAPA =====
|
||||||
|
provider = controller.get_table_map_provider()
|
||||||
|
self.map_widget = RoomTableMapWidget(
|
||||||
|
provider=provider,
|
||||||
|
on_select=None,
|
||||||
|
)
|
||||||
|
self.map_widget.edit_mode = True
|
||||||
|
root.add_widget(self.map_widget)
|
||||||
|
# ===== TOOLBAR DOLE =====
|
||||||
|
toolbar = BoxLayout(
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(70),
|
||||||
|
spacing=5,
|
||||||
|
padding=5,
|
||||||
|
)
|
||||||
|
btn_add = Button(text="+ Stůl")
|
||||||
|
btn_add_room = Button(text="+ Místnost")
|
||||||
|
btn_save_room = Button(text="Uložit\nmístnost")
|
||||||
|
btn_delete_room = Button(text="Smazat\nmístnost")
|
||||||
|
btn_load_room = Button(text="Načíst\nmístnost")
|
||||||
|
btn_save_all = Button(text="Uložit vše\nna server")
|
||||||
|
btn_back = Button(text="Zpět uložit\njen do paměti")
|
||||||
|
btn_cancel = Button(text="Zrušit")
|
||||||
|
# bindy
|
||||||
|
btn_add.bind(on_press=self._add_table)
|
||||||
|
btn_add_room.bind(on_press=self._add_room)
|
||||||
|
btn_save_room.bind(on_press=self._save_room)
|
||||||
|
btn_delete_room.bind(on_press=self._delete_room)
|
||||||
|
btn_load_room.bind(on_press=self._load_room_dialog)
|
||||||
|
btn_save_all.bind(on_press=self._save_all)
|
||||||
|
btn_back.bind(on_press=self._go_back)
|
||||||
|
btn_cancel.bind(on_press=self._cancel)
|
||||||
|
# přidání tlačítek
|
||||||
|
toolbar.add_widget(btn_add)
|
||||||
|
toolbar.add_widget(btn_add_room)
|
||||||
|
toolbar.add_widget(btn_save_room)
|
||||||
|
toolbar.add_widget(btn_delete_room)
|
||||||
|
toolbar.add_widget(btn_load_room)
|
||||||
|
toolbar.add_widget(btn_save_all)
|
||||||
|
toolbar.add_widget(btn_back)
|
||||||
|
toolbar.add_widget(btn_cancel)
|
||||||
|
root.add_widget(toolbar)
|
||||||
|
# ===== FINAL =====
|
||||||
|
self.add_widget(root)
|
||||||
|
# načtení mapy
|
||||||
|
self.map_widget.refresh()
|
||||||
|
|
||||||
|
def _go_back(self, *_):
|
||||||
|
from kivy.app import App
|
||||||
|
self._save_room()
|
||||||
|
app = App.get_running_app()
|
||||||
|
main = app.root.get_screen(self.back_screen)
|
||||||
|
if hasattr(main, "map_widget"):
|
||||||
|
main.map_widget.refresh()
|
||||||
|
app.root.current = self.back_screen
|
||||||
|
app.root.remove_widget(self)
|
||||||
|
|
||||||
|
def _delete_room(self, *_):
|
||||||
|
room_name = self.map_widget.current_room
|
||||||
|
if not room_name:
|
||||||
|
print("Není vybraná místnost")
|
||||||
|
return
|
||||||
|
# ===== potvrzovací dialog =====
|
||||||
|
layout = BoxLayout(orientation="vertical", spacing=10, padding=10)
|
||||||
|
layout.add_widget(Label(
|
||||||
|
text=f"Opravdu smazat místnost?\n\n{room_name}",
|
||||||
|
halign="center"
|
||||||
|
))
|
||||||
|
btn_yes = Button(text="ANO – smazat")
|
||||||
|
btn_no = Button(text="Ne")
|
||||||
|
layout.add_widget(btn_yes)
|
||||||
|
layout.add_widget(btn_no)
|
||||||
|
popup = Popup(
|
||||||
|
title="Smazání místnosti",
|
||||||
|
content=layout,
|
||||||
|
size_hint=(0.5, 0.4),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
def do_delete(_):
|
||||||
|
rooms = self.controller.mapa_stolu.rooms
|
||||||
|
# ===== smaž místnost =====
|
||||||
|
new_rooms = []
|
||||||
|
for r in rooms:
|
||||||
|
rn = r["room_name"] if isinstance(r, dict) else r.room_name
|
||||||
|
if rn != room_name:
|
||||||
|
new_rooms.append(r)
|
||||||
|
self.controller.mapa_stolu.rooms = new_rooms
|
||||||
|
# ===== přepnutí na jinou =====
|
||||||
|
if new_rooms:
|
||||||
|
first = new_rooms[0]
|
||||||
|
self.map_widget.current_room = (
|
||||||
|
first["room_name"] if isinstance(first, dict) else first.room_name
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.map_widget.current_room = None
|
||||||
|
self.map_widget.refresh()
|
||||||
|
popup.dismiss()
|
||||||
|
print(f"Smazána místnost: {room_name}")
|
||||||
|
btn_yes.bind(on_press=do_delete)
|
||||||
|
btn_no.bind(on_press=lambda *_: popup.dismiss())
|
||||||
|
popup.open()
|
||||||
|
|
||||||
|
def _add_room(self, *_):
|
||||||
|
layout = BoxLayout(orientation="vertical", spacing=5, padding=5)
|
||||||
|
name_in = TextInput(
|
||||||
|
text="Nová místnost",
|
||||||
|
multiline=False,
|
||||||
|
)
|
||||||
|
btn_ok = Button(text="Vytvořit")
|
||||||
|
btn_cancel = Button(text="Zrušit")
|
||||||
|
layout.add_widget(Label(text="Název místnosti"))
|
||||||
|
layout.add_widget(name_in)
|
||||||
|
layout.add_widget(btn_ok)
|
||||||
|
layout.add_widget(btn_cancel)
|
||||||
|
popup = Popup(
|
||||||
|
title="Nová místnost",
|
||||||
|
content=layout,
|
||||||
|
size_hint=(0.5, 0.4),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
def create(_):
|
||||||
|
name = name_in.text.strip()
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
# ===== kontrola duplicity =====
|
||||||
|
for r in self.controller.mapa_stolu.rooms:
|
||||||
|
rn = r["room_name"] if isinstance(r, dict) else r.room_name
|
||||||
|
if rn == name:
|
||||||
|
print("Místnost již existuje")
|
||||||
|
return
|
||||||
|
new_room = data.Room(
|
||||||
|
room_name=name,
|
||||||
|
stoly=[],
|
||||||
|
)
|
||||||
|
# ===== přidání =====
|
||||||
|
self.controller.mapa_stolu.rooms.append(new_room)
|
||||||
|
# ===== přepnutí =====
|
||||||
|
self.map_widget.current_room = name
|
||||||
|
self.map_widget.refresh()
|
||||||
|
popup.dismiss()
|
||||||
|
print(f"Vytvořena místnost: {name}")
|
||||||
|
btn_ok.bind(on_press=create)
|
||||||
|
btn_cancel.bind(on_press=lambda *_: popup.dismiss())
|
||||||
|
popup.open()
|
||||||
|
|
||||||
|
def _add_table(self, *_):
|
||||||
|
room = self.map_widget.current_room or "Room"
|
||||||
|
# ===== existující ID v aktuální místnosti =====
|
||||||
|
existing_ids = {
|
||||||
|
str(w.table.id).split("|")[-1]
|
||||||
|
for w in self.map_widget.map_area.children
|
||||||
|
}
|
||||||
|
i = 1
|
||||||
|
while str(i) in existing_ids:
|
||||||
|
i += 1
|
||||||
|
short_id = str(i)
|
||||||
|
new_id = f"{room}|{short_id}"
|
||||||
|
# ===== vytvoření stolu =====
|
||||||
|
t = data.Table(
|
||||||
|
id=new_id,
|
||||||
|
name=f"Stůl {short_id}",
|
||||||
|
pos_x=10,
|
||||||
|
pos_y=MAP_H - 120,
|
||||||
|
width=100,
|
||||||
|
height=100,
|
||||||
|
radius=0.2,
|
||||||
|
)
|
||||||
|
# ===== widget =====
|
||||||
|
w = TableWidget(t, state=None, on_press=None)
|
||||||
|
w.edit_mode = True
|
||||||
|
w.size_hint = (None, None)
|
||||||
|
w.size = (dp(t.width), dp(t.height))
|
||||||
|
w.pos = (dp(t.pos_x), dp(t.pos_y))
|
||||||
|
self.map_widget.map_area.add_widget(w)
|
||||||
|
w._update()
|
||||||
|
print(f"Přidán stůl {new_id}")
|
||||||
|
|
||||||
|
def _save_room(self, *_):
|
||||||
|
room_name = self.map_widget.current_room
|
||||||
|
if not room_name:
|
||||||
|
print("Není vybraná místnost")
|
||||||
|
return
|
||||||
|
tables = []
|
||||||
|
for w in reversed(self.map_widget.map_area.children):
|
||||||
|
t = w.table
|
||||||
|
t.pos_x = int(w.pos[0] / Metrics.density)
|
||||||
|
t.pos_y = int(w.pos[1] / Metrics.density)
|
||||||
|
t.width = int(w.size[0] / Metrics.density)
|
||||||
|
t.height = int(w.size[1] / Metrics.density)
|
||||||
|
tables.append(t)
|
||||||
|
for room in self.controller.mapa_stolu.rooms:
|
||||||
|
room_name_value = room.room_name if hasattr(room, "room_name") else room["room_name"]
|
||||||
|
if room_name_value == room_name:
|
||||||
|
if hasattr(room, "stoly"):
|
||||||
|
room.stoly = tables
|
||||||
|
else:
|
||||||
|
room["stoly"] = tables
|
||||||
|
break
|
||||||
|
print(f"Uložena místnost: {room_name}")
|
||||||
|
|
||||||
|
def _save_all(self, *_):
|
||||||
|
from ui_utils import _popup_info
|
||||||
|
try:
|
||||||
|
self._save_room()
|
||||||
|
ok, resp = self.controller.save_mapa_stolu()
|
||||||
|
if ok:
|
||||||
|
_popup_info("Mapa", "Mapa uložena na server")
|
||||||
|
else:
|
||||||
|
_popup_info("Chyba", str(resp))
|
||||||
|
except Exception as e:
|
||||||
|
_popup_info("Chyba", str(e))
|
||||||
|
|
||||||
|
def _cancel(self, *_):
|
||||||
|
from kivy.app import App
|
||||||
|
app = App.get_running_app()
|
||||||
|
app.root.current = self.back_screen
|
||||||
|
app.root.remove_widget(self)
|
||||||
|
|
||||||
|
def _load_room_dialog(self, *_):
|
||||||
|
btn_h = dp(50)
|
||||||
|
# ===== ROOT =====
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=5,
|
||||||
|
padding=5,
|
||||||
|
)
|
||||||
|
popup = Popup(
|
||||||
|
title="Načíst místnost",
|
||||||
|
content=root,
|
||||||
|
size_hint=(0.5, 0.6),
|
||||||
|
auto_dismiss=False,
|
||||||
|
)
|
||||||
|
# FIXNÍ ZPĚT
|
||||||
|
btn_back = Button(
|
||||||
|
text="Zpět",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=btn_h,
|
||||||
|
)
|
||||||
|
btn_back.bind(on_press=popup.dismiss)
|
||||||
|
root.add_widget(btn_back)
|
||||||
|
# SCROLL MÍSTNOSTI
|
||||||
|
scroll = ScrollView(
|
||||||
|
size_hint=(1, 1),
|
||||||
|
do_scroll_y=True,
|
||||||
|
do_scroll_x=False,
|
||||||
|
bar_width=dp(10),
|
||||||
|
)
|
||||||
|
room_list = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
size_hint_y=None,
|
||||||
|
spacing=5,
|
||||||
|
)
|
||||||
|
room_list.bind(minimum_height=room_list.setter("height"))
|
||||||
|
for room in self.controller.mapa_stolu.rooms:
|
||||||
|
room_name = room["room_name"] if isinstance(room, dict) else room.room_name
|
||||||
|
btn = Button(
|
||||||
|
text=room_name,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=btn_h,
|
||||||
|
)
|
||||||
|
def load_room(instance, name=room_name):
|
||||||
|
self.map_widget.current_room = name
|
||||||
|
self.map_widget.refresh()
|
||||||
|
popup.dismiss()
|
||||||
|
btn.bind(on_press=load_room)
|
||||||
|
room_list.add_widget(btn)
|
||||||
|
scroll.add_widget(room_list)
|
||||||
|
root.add_widget(scroll)
|
||||||
|
popup.open()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,430 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
TRUNCATE _zoznam RESTART IDENTITY CASCADE;
|
||||||
|
|
||||||
|
INSERT INTO "public"."_zoznam"(
|
||||||
|
"key" ,"value" ,"typ","var_typ","comment" ,"supervisor","poradie","skupina","var_valid" ,"var_ponuka" ,"var_kontr" ,"comment2","j0","j1","j2","j3","j4","inp_mask","pristup")
|
||||||
|
VALUES
|
||||||
|
---
|
||||||
|
--- CCD
|
||||||
|
---
|
||||||
|
(E'ccd_com',E'0',E'param',E'N',E'Com port citacky ciaroveho kodu ',1,1 ,E'CCD ',E'',E'',E'',E'',E'Com port citacky ciaroveho kodu ',E'Com port citacky ciaroveho kodu ',E'',E'',E'',E'',0),
|
||||||
|
(E'ccd_baud',E'4800',E'param',E'N',E'Baud rate citacky ciaroveho kodu ',1,2 ,E'CCD ',E'',E',19200,9600,4800,2400,1200 ',E'ccd_com;<>;0 ',E'',E'Baud rate citacky ciaroveho kodu ',E'Baud rate citacky ciaroveho kodu ',E'',E'',E'',E'',0),
|
||||||
|
(E'ccd_bit',E'8',E'param',E'N',E'Dat. bity citacky ciaroveho kodu ',1,3 ,E'CCD ',E'',E',5,6,7,8 ',E'ccd_com;<>;0 ',E'',E'Dat. bity citacky ciaroveho kodu ',E'Dat. bity citacky ciaroveho kodu ',E'',E'',E'',E'',0),
|
||||||
|
(E'ccd_par',E'0',E'param',E'N',E'Parita citacky ciaroveho kodu ',1,4 ,E'CCD ',E'',E',0,1,2 ',E'ccd_com;<>;0 ',E'',E'Parita citacky ciaroveho kodu ',E'Parita citacky ciaroveho kodu ',E'',E'',E'',E'',0),
|
||||||
|
(E'ccd_stop',E'1',E'param',E'N',E'Stopbity citacky ciaroveho kodu ',1,5 ,E'CCD ',E'',E',0,1,2 ',E'ccd_com;<>;0 ',E'',E'Stopbity citacky ciaroveho kodu ',E'Stopbity citacky ciaroveho kodu ',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- COOK
|
||||||
|
---
|
||||||
|
(E'cook_new_interval_color',E'"#228ae6"',E'param',E'C',E'Aká má byť farba nových položiek? ',0,0 ,E'COOK',E'',E'',E'',E'',E'Aká má byť farba nových položiek?',E'Aká má byť farba nových položiek?',E'',E'',E'',E'',0),
|
||||||
|
(E'cook_new_interval_minutes',E'5',E'param',E'N',E'Ako dlho má byť položka ozačená ako nová? ',0,0 ,E'COOK',E'',E'',E'',E'',E'Ako dlho má byť položka ozačená ako nová?',E'Ako dlho má byť položka ozačená ako nová?',E'',E'',E'',E'',0),
|
||||||
|
(E'cook_done_expire_minutes',E'5',E'param',E'N',E'Koľko minút sa zobrazuje hotové jedlo?',0,0 ,E'COOK',E'',E'',E'',E'',E'Koľko minút sa zobrazuje hotové jedlo?',E'Koľko minút sa zobrazuje hotové jedlo?',E'',E'',E'',E'',0),
|
||||||
|
(E'cook_notification_sound_enable',E'.F.',E'param',E'L',E'Zapnúť zvukovú notifikáciu na novú objednávku?',0,0 ,E'COOK',E'',E'',E'',E'',E'Zapnúť zvukovú notifikáciu na novú objednávku?',E'Zapnúť zvuk notifikáciu na novú objednávku?',E'',E'',E'',E'',0),
|
||||||
|
(E'cook_notification_sound',E'"default"',E'param',E'C',E'Typ zvukovej notifikácie na novú objednávku',0,0 ,E'COOK',E'',E'',E'',E'',E'Typ zvukovej notifikácie na novú objednávku',E'Typ zvuk notifikácie na novú objednávku',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- E-SHOP
|
||||||
|
---
|
||||||
|
(E'eshop_auto_progress',E'.F.',E'param',E'L',E'Automaticky nastaviť stav eshop objednávky na v procese? ',0,0 ,E'ESHOP',E'',E'',E'',E'',E'Automaticky nastaviť stav eshop objednávky?',E'Automaticky nastaviť stav eshop objednávky?',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- FISKAL
|
||||||
|
---
|
||||||
|
(E'oznacenie',E'"FOOD600"',E'param',E'C',E'Oznacenie pokladne podla certifikat ',0,3 ,E'FISKAL ',E'',E'',E'',E'',E'Oznacenie pokladne podla certifikat ',E'Oznacenie pokladne podla certifikat ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_fiskal',E'.T.',E'param',E'L',E'.T. - je to fiskalizovana kasa, .F. nie je fiskalizovana ',1,1 ,E'FISKAL ',E'',E'',E'',E'',E'.T. - je to fiskalizovana kasa, .F. nie je fiskali',E'.T. - je to fiskalizovana kasa, .F. nie je fiskali',E'',E'',E'',E'',0),
|
||||||
|
(E'fiskal_typ',E'"ALTO"',E'fiskal',E'C',E'Typ fiskalneho modulu "UPOS", "BOWA", "ALTO", "" ',1,2 ,E'FISKAL ',E'',E',ALTO,BOWA,UPOS,ALTO289 ',E'',E'Typ fiskalneho modulu \nHodnoty: \nALTO - alto fiskal, podla stareho zakona sofverovy(DEFAULT NASTAVENIE)\nBOWA - fiskal od firmy BOWA\nUPOS - fiskal od firmy UPOS\n',E'Typ fiskalneho modulu "UPOS", "BOWA", "ALTO", "" ',E'Typ fiskalneho modulu "UPOS", "BOWA", "ALTO", "" ',E'',E'',E'',E'',0),
|
||||||
|
(E'fiskal_sp_pohladavka',E'"\'@\'"',E'param',E'C',E'Zoznam spartov oznacujuci uhrady pohladavok ',1,25,E'FISKAL ',E'',E'',E'',E'Zoznam špartov, kotré uznačujú skupiny slúžiace na úhradu pohľadávok.',E'Zoznam spartov oznacujuci uhrady pohladavok ',E'Zoznam spartov oznacujuci uhrady pohladavok ',E'',E'',E'',E'multi;spart_kas;@',0),
|
||||||
|
(E'spart_zaloha',E'"\'@\'"',E'param',E'C',E'Zoznam spartov pre zalohu ',0,22,E'FISKAL ',E'',E'',E'',E'',E'Zoznam spartov pre zalohu ',E'Zoznam spartov pre zalohu ',E'Zoznam spartov pre zalohu ',E'Zoznam spartov pre zalohu ',E'Zoznam spartov pre zalohu ',E'multi;spart_kas;@',0),
|
||||||
|
(E'spart_obaly',E'"\'@\'"',E'param',E'C',E'Zoznam spartov pre obaly ',0,23,E'FISKAL ',E'',E'',E'',E'',E'Zoznam spartov pre obaly ',E'Zoznam spartov pre obaly ',E'Zoznam spartov pre obaly ',E'Zoznam spartov pre obaly ',E'Zoznam spartov pre obaly ',E'multi;spart_kas;@',0),
|
||||||
|
(E'ekasa',E'.T.',E'param',E'L',E'eKasa ',0,21,E'FISKAL',E'',E'',E'',E'',E'eKasa',E'eKasa',E'',E'',E'',E'',0),
|
||||||
|
(E'info_warning_periodicity_seconds',E'"3600"',E'param',E'C',E'Ako často v sekundách zobraziť upozornenia z AFS ?',0,23 ,E'FISKAL',E'',E'',E'',E'',E'Ako často v sekundách zobraziť upozornenia z AFS ?',E'Ako často v sekundách zobraziť upozornenia z AFS ?',E'',E'',E'',E'',0),
|
||||||
|
(E'error_500001_assume_ekas_registration_failed',E'.t.',E'param',E'L',E'Pri chybe registracie úctu na FS neklásť otázky?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'Pri chybe registracie úctu na FS neklásť otázky?',E'Pri chybe registracie úctu na FS neklásť otázky?',E'',E'',E'',E'',0),
|
||||||
|
(E'error_500003_assume_card_payment_failed',E'.t.',E'param',E'L',E'Pri chybe komunikácie s term. neklásť otázky?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'Pri chybe komunikácie s term. neklásť otázky?',E'Pri chybe komunikácie s term. neklásť otázky?',E'',E'',E'',E'',0),
|
||||||
|
(E'payment_allow_without_bill_printing_',E'.f.',E'param',E'L',E'Je mozne uzavriet platbu bez tlace uctu?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'Je mozne uzavriet platbu bez tlace uctu?',E'Je mozne uzavriet platbu bez tlace uctu?',E'',E'',E'',E'',0),
|
||||||
|
(E'payment_default_print_bill_',E'.t.',E'param',E'L',E'Ak sa netlaci ucet, predvolit v otazke ANO?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'Ak sa netlaci ucet, predvolit v otazke ANO?',E'Ak sa netlaci ucet, predvolit v otazke ANO?',E'',E'',E'',E'',0),
|
||||||
|
(E'payment_default_email_bill_',E'.f.',E'param',E'L',E'Predvolene posielať účty emailom?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'Predvolene posielať účty emailom?',E'Predvolene posielať účty emailom?',E'',E'',E'',E'',0),
|
||||||
|
(E'fiskalpro_index_from_cisfplat',E'.f.',E'param',E'L',E'FiskalPRO - posielat ako index platby cisfplat?',0,0 ,E'FISKAL',E'',E'',E'',E'',E'FiskalPRO - posielat ako index platby cisfplat?',E'FiskalPRO - posielat ako index platby cisfplat?',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- HOTEL
|
||||||
|
---
|
||||||
|
(E'is_hores',E'.F.',E'param',E'L',E'Vazba na HORES (HRMC) ',0,1 ,E'HOTEL',E'',E'',E'',E'',E'Vazba na HORES (HRMC) ',E'Vazba na HORES (HRMC) ',E'',E'',E'',E'',0),
|
||||||
|
(E'typ_hotel',E'1',E'param',E'N',E'Typ recepcie ',0,2 ,E'HOTEL',E'',E',6,10,17,18,21 ',E'',E'6 - Opera, 10 - Protel, 17 - Hores10,18 - Previo,21 - Mews',E'Typ recepcie ',E'Typ recepcie ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_uzprenh',E'.F.',E'param',E'L',E'Automat.prenos tržieb do Horesu ',0,3 ,E'HOTEL',E'',E'',E'',E'',E'Automat.přenos tržeb do Horesu ',E'Automat.přenos tržeb do Horesu ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_uzprenhtimeatr',E'.f.',E'param',E'L',E'.T. - rozne nastavnie rastrov pre rozne casy (tmatr1) -uzav.',0,4 ,E'HOTEL',E'',E'',E'',E'',E'.T. - rozne nastavnie rastrov pre rozne casy (tmat',E'.T. - rozne nastavnie rastrov pre rozne casy (tmat',E'',E'',E'',E'',0),
|
||||||
|
(E'rastr_hot',E'.F.',E'param',E'L',E'.F. sumárny prenos po rastroch, .T. prenos po položkách ',0,5 ,E'HOTEL',E'',E'',E'',E'',E'',E'',E'',E'',E'',E'',0),
|
||||||
|
(E'hotel_karta_typ',E'"SALTO"',E'param',E'C',E'Typ kódovania hotelovej karty ',0,6 ,E'HOTEL',E'',E',SALTO,MAG',E'',E'',E'Typ kódovania hotelovej karty',E'Typ kódovania hotelovej karty',E'',E'',E'',E'',0),
|
||||||
|
(E'a8_scanner',E'.T.',E'param',E'L',E'Čítanie hotelových kariet na A8 ',0,7 ,E'HOTEL',E'',E'',E'',E'',E'Čítanie hotelových kariet na A8',E'Čítanie hotelových kariet na A8',E'',E'',E'',E'',0),
|
||||||
|
(E'hotel_karta_length',E'14',E'param',E'N',E'Počet znakov hotelovej karty ',0,8 ,E'HOTEL',E'',E'',E'',E'',E'Počet znakov hotelovej karty',E'Počet znakov hotelovej karty',E'',E'',E'',E'',0),
|
||||||
|
(E'is_horskup',E'.T.',E'param',E'L',E'Naťažovať do Horesu na skupiny ',0,9 ,E'HOTEL ',E'',E'',E'',E'',E'Naťažovať do Horesu na skupiny',E'Naťažovať do Horesu na skupiny',E'',E'',E'',E'',0),
|
||||||
|
(E'is_zapltiz',E'.T.',E'param',E'L',E'Povolené naťažovanie do Horesu na zaplatené účty.',0,10 ,E'HOTEL',E'',E'',E'',E'',E'Povolené naťažovanie do Horesu na zaplatené účty.',E'Povolené naťažovanie do Horesu na zaplatené účty.',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- KARTY
|
||||||
|
---
|
||||||
|
(E'karta_baud',E'9600',E'param',E'N',E'Baud rate čítačky hotelových kariet ',1,2 ,E'KARTY ',E'',E',19200,9600,4800,2400,1200 ',E'karty_typ;!EMPT; ',E'',E'Baud rate čítačky hotelových kariet ',E'Baud rate čítačky hotelových kariet ',E'',E'',E'',E'',0),
|
||||||
|
(E'karta_bit',E'8',E'param',E'N',E'Dat. bity čítačky hotelových kariet ',1,3 ,E'KARTY ',E'',E',5,6,7,8 ',E'karty_typ;!EMPT; ',E'',E'Dat. bity čítačky hotelových kariet ',E'Dat. bity čítačky hotelových kariet ',E'',E'',E'',E'',0),
|
||||||
|
(E'karta_com',E'0',E'param',E'N',E'Com port čítačky hotelových kariet ',1,4 ,E'KARTY ',E'',E'',E'karty_typ;!EMPT; ',E'',E'Com port čítačky hotelových kariet ',E'Com port čítačky hotelových kariet ',E'',E'',E'',E'',0),
|
||||||
|
(E'karta_par',E'0',E'param',E'N',E'Parita čítačky hotelových kariet ',1,5 ,E'KARTY ',E'',E',0,1,2 ',E'karty_typ;!EMPT; ',E'',E'Parita čítačky hotelových kariet ',E'Parita čítačky hotelových kariet ',E'',E'',E'',E'',0),
|
||||||
|
(E'karta_stop',E'1',E'param',E'N',E'Stopbity čítačky hotelových kariet ',1,6 ,E'KARTY ',E'',E',0,1,2 ',E'karty_typ;!EMPT; ',E'',E'Stopbity čítačky hotelových kariet ',E'Stopbity čítačky hotelových kariet ',E'',E'',E'',E'',0),
|
||||||
|
(E'pwd_baud',E'4800',E'param',E'N',E'Baud rate ctecky hesel ',1,8 ,E'KARTY ',E'',E',19200,9600,4800,2400,1200 ',E'pwd_typ;!EMPT; ',E'',E'Baud rate ctecky hesel ',E'Baud rate ctecky hesel ',E'',E'',E'',E'',0),
|
||||||
|
(E'pwd_bit',E'8',E'param',E'N',E'Dat. bity ctecky hesel ',1,9 ,E'KARTY ',E'',E',5,6,7,8 ',E'pwd_typ;!EMPT; ',E'',E'Dat. bity ctecky hesel ',E'Dat. bity ctecky hesel ',E'',E'',E'',E'',0),
|
||||||
|
(E'pwd_com',E'0',E'param',E'N',E'Com port ctecky hesel ',1,10,E'KARTY ',E'',E'',E'pwd_typ;!EMPT; ',E'',E'Com port ctecky hesel ',E'Com port ctecky hesel ',E'',E'',E'',E'',0),
|
||||||
|
(E'pwd_par',E'0',E'param',E'N',E'Parita ctecky hesel ',1,11,E'KARTY ',E'',E',0,1,2 ',E'pwd_typ;!EMPT; ',E'',E'Parita ctecky hesel ',E'Parita ctecky hesel ',E'',E'',E'',E'',0),
|
||||||
|
(E'pwd_stop',E'1',E'param',E'N',E'Stopbity ctecky hesel ',1,12,E'KARTY ',E'',E',0,1,2 ',E'pwd_typ;!EMPT; ',E'',E'Stopbity ctecky hesel ',E'Stopbity ctecky hesel ',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- OBJEDNAVKA
|
||||||
|
---
|
||||||
|
(E'kc_spart',E'"UHF"',E'param',E'C',E'Spart pre polozky s volnou cenou ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Spart pro obecnou korunovou polozku ',E'Spart pro obecnou korunovou polozku ',E'',E'',E'',E'multi;spart_kas;UHF',0),
|
||||||
|
(E'def_cenhla',E'"1"',E'param',E'C',E'Default úroveň ceny ',0,11,E'OBJEDNAVKA',E'',E'',E'',E'',E'Default úroveň ceny ',E'Default úroveň ceny ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_sumobj',E'.t.',E'param',E'L',E'sumarizovat objednavky ',0,10,E'OBJEDNAVKA',E'',E'',E'',E'',E'sumarizovat objednavky ',E'sumarizovat objednavky ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_objnul',E'.F.',E'param',E'L',E'objednavka s nulovou cenou ',0,8 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'objednavka s nulovou cenou ',E'objednavka s nulovou cenou ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_zapobj',E'.F.',E'param',E'L',E'Objednavka se zapornym poctem ',1,9 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Objednavka se zapornym poctem ',E'Objednavka se zapornym poctem ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_saldo',E'.T.',E'param',E'L',E'Zobrazovat mezisoucet v objednavce ',0,29,E'OBJEDNAVKA',E'',E'',E'',E'',E'Zobrazovat mezisoucet v objednavce ',E'Zobrazovat mezisoucet v objednavce ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_fulltch',E'.T.',E'param',E'L',E'Plny popis klapek ',0,30,E'OBJEDNAVKA',E'',E'',E'',E'',E'Plny popis klapek ',E'Plny popis klapek ',E'',E'',E'',E'',0),
|
||||||
|
---Pokud to bude respektovat nastavení u skupin (E'koef_c_2',E'0.5',E'param',E'N',E'Koeficient ceny polovicni porce ',0,26,E'OBJEDNAVKA',E'',E'',E'',E'',E'Koeficient ceny polovicni porce ',E'Koeficient ceny polovicni porce ',E'',E'',E'',E'',0),
|
||||||
|
---Pokud to bude respektovat nastavení u skupin (E'koef_c_3',E'0.33',E'param',E'N',E'Koeficient ceny tretinova porce ',0,27,E'OBJEDNAVKA',E'',E'',E'',E'',E'Koeficient ceny tretinova porce ',E'Koeficient ceny tretinova porce ',E'',E'',E'',E'',0),
|
||||||
|
---Pokud to bude respektovat nastavení u skupin (E'koef_c_4',E'0.25',E'param',E'N',E'Koeficient ceny ctvrtinova porce ',0,28,E'OBJEDNAVKA',E'',E'',E'',E'',E'Koeficient ceny ctvrtinova porce ',E'Koeficient ceny ctvrtinova porce ',E'',E'',E'',E'',0),
|
||||||
|
(E'des_m_obj',E'0',E'param',E'N',E'Pocet desetin pro kolik v objednavc ',0,31,E'OBJEDNAVKA',E'',E'',E'',E'',E'Pocet desetin pro kolik v objednavc ',E'Pocet desetin pro kolik v objednavc ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_stolchl',E'.F.',E'param',E'L',E'Sú default cen.hl. pre stoly? ',0,33,E'OBJEDNAVKA',E'',E'',E'',E'',E'Sú default cen.hl. pre stoly? ',E'Sú default cen.hl. pre stoly? ',E'',E'',E'',E'',0),
|
||||||
|
(E'stob_lim',E'0',E'param',E'N',E'Limit na storno objednavek [min] ',0,50,E'OBJEDNAVKA',E'',E'',E'',E'',E'Limit na storno objednavek [min] ',E'Limit na storno objednavek [min] ',E'',E'',E'',E'',0),
|
||||||
|
--- přesunuto (E'vah_ident',E'"21"',E'param',E'C',E'Identifikace vazeneho zbozi na car. ',1,51,E'OBJEDNAVKA',E'',E'',E'',E'',E'Identifikace vazeneho zbozi na car. ',E'Identifikace vazeneho zbozi na car. ',E'',E'',E'',E'',0),
|
||||||
|
--- přesunuto (E'vah_lnplu',E'5',E'param',E'N',E'Delka kodu vazeneho zbozi na car.ko ',1,52,E'OBJEDNAVKA',E'',E'',E'',E'',E'Delka kodu vazeneho zbozi na car.ko ',E'Delka kodu vazeneho zbozi na car.ko ',E'',E'',E'',E'',0),
|
||||||
|
--- přesunuto (E'vah_lnvah',E'5',E'param',E'N',E'Delka kodu vahy na car.kodu ',1,53,E'OBJEDNAVKA',E'',E'',E'',E'',E'Delka kodu vahy na car.kodu ',E'Delka kodu vahy na car.kodu ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr2',E'"O"',E'param',E'C',E'Hodnota pro interval 2 ',0,16,E'OBJEDNAVKA',E'',E'',E'',E'',E'Hodnota pro interval 2 ',E'Hodnota pro interval 2 ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr1_chl',E'1',E'param',E'N',E'Cenová hladina pre čas.atribút 1 ',0,15,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cenová hladina pre čas.atribút 1 ',E'Cenová hladina pre čas.atribút 1 ',E'',E'',E'',E'',0),
|
||||||
|
(E'pouzit_cas_posledpol',E'.F.',E'param',E'L',E'Pri doobjednani použiť čas poslednej položky? ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'Pri doobjednani použiť čas posledne doobjednanej položky?',E'Pri doobjednani použiť čas poslednej položky? ',E'Pri doobjednani použiť čas poslednej položky? ',E'Pri doobjednani použiť čas poslednej položky? ',E'Pri doobjednani použiť čas poslednej položky? ',E'Pri doobjednani použiť čas poslednej položky? ',E'',0),
|
||||||
|
(E'ini_page_n',E'1',E'param',E'N',E'Číslo stranky klapek jako první ',0,7 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Číslo stranky klapek jako první ',E'Číslo stranky klapek jako první ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr4',E'"V"',E'param',E'C',E'Hodnota pro interval 4 ',0,22,E'OBJEDNAVKA',E'',E'',E'',E'',E'Hodnota pro interval 4 ',E'',E'',E'',E'',E'',0),
|
||||||
|
(E'objednavka_tlacitko1',E'"Hotove"',E'param',E'C',E'Variabilne nastavenie tlacitka 1 v objed. ',0,41,E'OBJEDNAVKA',E'',E'',E'',E'',E'Variabilne nastavenie tlacitka 1 v objed. ',E'Variabilne nastavenie tlacitka 1 v objed. ',E'',E'',E'',E'uni;druhy_pl;Hotove',0),
|
||||||
|
(E'tmatr2_chl',E'2',E'param',E'N',E'Cenová hladina pre čas.atribút 2 ',0,18,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cenová hladina pre čas.atribút 2 ',E'Cenová hladina pre čas.atribút 2 ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr1_on',E'"00:00:00"',E'param',E'C',E'Cas pro zapnuti intervalu 1 ',0,14,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cas pro zapnuti intervalu 1 ',E'Cas pro zapnuti intervalu 1 ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr2_on',E'"10:00:00"',E'param',E'C',E'Cas zapnuti intervalu 2 ',0,17,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cas zapnuti intervalu 2 ',E'Cas zapnuti intervalu 2 ',E'',E'',E'',E'',0),
|
||||||
|
(E'def_tmatr',E'"O"',E'param',E'C',E'Default time atribut ',0,12,E'OBJEDNAVKA',E'',E'',E'',E'',E'Default time atribut ',E'Default time atribut ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_mody',E'.F.',E'param',E'L',E'Používajú sa módy (R,O,V) ',1,32,E'OBJEDNAVKA',E'',E'',E'',E'',E'Používajú sa módy (R,O,V) ',E'Používajú sa módy (R,O,V) ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr1',E'"R"',E'param',E'C',E'Hodnota pro interval 1 ',0,13,E'OBJEDNAVKA',E'',E'',E'',E'',E'Hodnota pro interval 1 ',E'Hodnota pro interval 1 ',E'',E'',E'',E'',0),
|
||||||
|
(E'def_cenhlastob_lim',E'"1"',E'param',E'C',E'Default úroveň ceny ',0,11,E'OBJEDNAVKA',E'',E'',E'',E'',E'Default úroveň ceny ',E'Default úroveň ceny ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr3_chl',E'3',E'param',E'N',E'Cenová hladina pre čas.atribút 3 ',0,21,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cenová hladina pre čas.atribút 3 ',E'Cenová hladina pre čas.atribút 3 ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr3_on',E'"18:00:00"',E'param',E'C',E'Cas pro zapnuti intervalu 3 ',0,20,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cas pro zapnuti intervalu 3 ',E'Cas pro zapnuti intervalu 3 ',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr5_on',E'"23:59:59"',E'param',E'C',E'Cas pro zapnuti intervalu 5 ',0,25,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cas pro zapnuti intervalu 5 ',E'',E'',E'',E'',E'',0),
|
||||||
|
(E'tmatr5',E'"V"',E'param',E'C',E'Hodnota pro interval 5 ',0,24,E'OBJEDNAVKA',E'',E'',E'',E'',E'Hodnota pro interval 5 ',E'',E'',E'',E'',E'',0),
|
||||||
|
--- duplicita (E'des_m_obj',E'0',E'param',E'N',E'Pocet desetin pro kolik v objednavc ',0,31,E'OBJEDNAVKA',E'',E'',E'',E'',E'Pocet desetin pro kolik v objednavc ',E'Pocet desetin pro kolik v objednavc ',E'',E'',E'',E'',0),
|
||||||
|
(E'objednavka_tlacitko3',E'""',E'param',E'C',E'Variabilne nastavenie tlacitka "Platba so zlavou" v objed. ',0,43,E'OBJEDNAVKA',E'',E'',E'',E'',E'Variabilne nastavenie tlacitka "Platba so zlavou" ',E'Variabilne nastavenie tlacitka "Platba so zlavou" ',E'',E'',E'',E'uni;druhy_pl',0),
|
||||||
|
(E'tmatr3',E'"V"',E'param',E'C',E'Hodnota pro interval 3 ',0,19,E'OBJEDNAVKA',E'',E'',E'',E'',E'Hodnota pro interval 3 ',E'Hodnota pro interval 3 ',E'',E'',E'',E'',0),
|
||||||
|
(E'objednavka_tlacitko2',E'""',E'param',E'C',E'Variabilne nastavenie tlacitka "Subtotal" v objed. ',0,42,E'OBJEDNAVKA',E'',E'',E'',E'',E'Variabilne nastavenie tlacitka "Subtotal" v objed.',E'Variabilne nastavenie tlacitka "Subtotal" v objed.',E'',E'',E'',E'uni;druhy_pl',0),
|
||||||
|
(E'tmatr4_on',E'"23:59:58"',E'param',E'C',E'Cas pro zapnuti intervalu 4 ',0,23,E'OBJEDNAVKA',E'',E'',E'',E'',E'Cas pro zapnuti intervalu 4 ',E'',E'',E'',E'',E'',0),
|
||||||
|
(E'menu_spart',E'"FST"',E'param',E'C',E'Spart oznacujici fastfood menu ',1,3 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Spart oznacujici fastfood menu ',E'Spart oznacujici fastfood menu ',E'',E'',E'',E'uni;spart_kas;FST',0),
|
||||||
|
(E'obj_fstmenu_radit_sp',E'true',E'param',E'L',E'V objednavke radit a spocitat fst menu podla nastavenia skup',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'V objednavke radit a spocitat fst menu podla nastp',E'V objednavke radit a spocitat fst menu podla nastp',E'V objednavke radit a spocitat fst menu podla nastp',E'',E'',E'',0),
|
||||||
|
(E'mnusp600',E'"MNU"',E'param',E'C',E'Spart označujúci menu Food600 ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Spart označujúci menu Food600 ',E'Spart označujúci menu Food600 ',E'Spart označujúci menu Food600 ',E'Spart označujúci menu Food600 ',E'Spart označujúci menu Food600 ) ',E'uni;spart_kas;MNU',0),
|
||||||
|
--- přesunuto (E'hk_sl_spl',E'"XXX"',E'param',E'C',E'Zoznam spartov, na ktoré sa nedáva zľava ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Zoznam spartov, na ktoré sa nedáva zľava',E'Zoznam spartov, na ktoré sa nedáva zľava',E'',E'',E'',E'multi;spart_kas;@',0),
|
||||||
|
(E'bon_show_prices',E'.T.',E'param',E'L',E'Má bon zobrazovať sumu položky? ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Má bon zobrazovať sumu položky?',E'Má bon zobrazovať sumu položky?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_stulres_plat',E'.F.',E'param',E'L',E'Má zakázať čašníkovi vyplatiť stôl iného? ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Má zakázať čašníkovi vyplatiť stôl iného?',E'Má zakázať čašníkovi vyplatiť stôl iného?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_stulres',E'.F.',E'param',E'L',E'Má zakázať čašníkovi meniť položky iného? ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Má zakázať čašníkovi meniť položky iného?',E'Má zakázať čašníkovi meniť položky iného?',E'',E'',E'',E'',0),
|
||||||
|
(E'binary_revert_card_read',E'.F.',E'param',E'L',E'Majú sa binárne invertovať načítané karty? ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Majú sa binárne invertovať načítané karty?',E'Majú sa binárne invertovať načítané karty?',E'',E'',E'',E'',0),
|
||||||
|
(E'search_item_size',E'3',E'param',E'N',E'Na koľko polí sa má zobraziť výsledok hľadania? ',0,0 ,E'OBJEDNAVKA',E'',E'1,2,3,4,5,6,7 ',E'',E'Udáva sa na aký násobok 3 sa majú zobraziť klapky po vyhľadávaní. Ak je param väčší ako 7 tak to nastaví na 7',E'Na koľko polí sa má zobraziť výsledok hľadania?',E'Na koľko polí sa má zobraziť výsledok hľadania?',E'',E'',E'',E'',0),
|
||||||
|
(E'orderline_pager',E'.F.',E'param',E'L',E'Používa sa pager na privolávanie zákazníkov ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Používa sa pager pre zákazníkov?',E'Používa sa pager pre zákazníkov?',E'',E'',E'',E'',0),
|
||||||
|
(E'auto_chod',E'.F.',E'param',E'L',E'Automaticky natiahnuť chod z položky? ',0,9 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Automaticky natiahnuť chod z položky?',E'Automaticky natiahnuť chod z položky?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_koef_portion',E'.T.',E'param',E'L',E'Počítať cenu čiastkových porcií koeficientom? ',0,9 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Počítať cenu čiastkových porcií koeficientom?',E'Počítať cenu čiastkových porcií koeficientom?',E'',E'',E'',E'',0),
|
||||||
|
(E'last_added_item_count',E'3',E'param',E'N',E'Počet zobrazených riadkov v objednávke na mobile ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Počet zobrazených riadkov v objednávke na mobile',E'Počet zobrazených riadkov v objednávke na mobile',E'',E'',E'',E'',0),
|
||||||
|
(E'order_line_swipeable_group',E'.t.',E'param',E'L',E'Je možné množstvo menit ťahaním prsta? ',0,19,E'OBJEDNAVKA',E'',E'',E'',E'',E'Množstvo je možné meniť cez swipe',E'Množstvo je možné meniť cez swipe',E'',E'',E'',E'',0),
|
||||||
|
(E'last_added_item_count',E'3',E'param',E'N',E'Počet zobrazených riadkov v objednávke na mobile ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Počet zobrazených riadkov v objednávke na mobile',E'Počet zobrazených riadkov v objednávke na mobile',E'',E'',E'',E'',0),
|
||||||
|
(E'ean_match_without_prefix_start_digits',E'""',E'param',E'C',E'Čím začína ean predváženého tovaru ak nemá prefix?',0,10 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'',E'Čím začína ean predváženého tovaru ak nemá prefix?',E'',E'',E'',E'',0),
|
||||||
|
(E'ean_match_without_prefix',E'.f.',E'param',E'L',E'Rozoznávať predvážený tovar bez prefixu?',0,10 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'',E'Rozoznávať predvážený tovar bez prefixu?',E'',E'',E'',E'',0),
|
||||||
|
(E'locators',E'.f.',E'param',E'L',E'Povolit lokátory / pagers?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Povolit lokátory / pagers?',E'Povolit lokátory / pagers?',E'',E'',E'',E'',0),
|
||||||
|
(E'last_added_items_change',E'.t.',E'param',E'L',E'Dá sa meniť nerozkliknutá objednávka ťahom?',0,13 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Dá sa meniť nerozkliknutá objednávka ťahom?',E'Dá sa meniť nerozkliknutá objednávka ťahom?',E'',E'',E'',E'',0),
|
||||||
|
(E'allow_portions_overcount',E'.t.',E'param',E'L',E'Umožniť nablokovať viac porcií ako je dostupných?',0,16 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Umožniť nablokovať viac porcií ako je dostupných?',E'Umožniť nablokovať viac porcií ako je dostupných?',E'',E'',E'',E'',0),
|
||||||
|
(E'app_order_bottom_buttons_sort',E'"[1,2,3,4,5,6,7,8,9,10,11]"',E'param',E'C',E'Poradie ikoniek pri rozkliknutej objednavke na mobile',0,16 ,E'OBJEDNAVKA',E'',E'',E'',E'plus - 1, porcia - 2, zľava - 3, zmazanie - 4, platba - 5, presun na stôl - 6, cenová hladina - 7, správa - 8, presun na chod - 9, presun na hosťa - 10, vybrať všetko - 11',E'Poradie ikoniek v objednávke na mobile',E'Poradie ikoniek v objednavke na mobile',E'',E'',E'',E'',0),
|
||||||
|
(E'on_table_close_ask_for_items_delete',E'.T.',E'param',E'L',E'Pýtať sa pri zatvorení stola na mazanie nepotvrdených pol.',0,60 ,E'OBJEDNAVKA',E'',E'',E'',E'Pýtať sa obsluhy pri zatvorení stola na mazanie nepotvrdených položiek',E'Pýtať sa pri zatvorení stola či zmazať nepotvrdené',E'Pýtať sa pri zatvorení stola či zmazať nepotvrdené',E'',E'',E'',E'',0),
|
||||||
|
(E'on_table_close_delete_items',E'.F.',E'param',E'L',E'Zmazať nepotvrd.pol.pri zatvorení stola(ak sa to nepýtame)',0,61 ,E'OBJEDNAVKA',E'',E'',E'',E'Zmazať nepotvrdené položky pri zatvorení stola (ak sa to nepýtame obsluhy)',E'Zmaž nepotv.pol.pri zatvorení stola(ak sa nepýtame',E'Zmaž nepotv.pol.pri zatvorení stola(ak sa nepýtame',E'',E'',E'',E'',0),
|
||||||
|
(E'hide_button_chystajchod',E'.F.',E'param',E'L',E'Skryť tlačítko Chystaj chod?',0,62 ,E'OBJEDNAVKA',E'',E'',E'',E'Skryť tlačítko Chystaj chod?',E'Skryť tlačítko Chystaj chod?',E'Skryť tlačítko Chystaj chod?',E'',E'',E'',E'',0),
|
||||||
|
(E'force_rename_foodcourse',E'.F.',E'param',E'L',E'Pomenovanie chodov pri ich zakladaní?',0,65 ,E'OBJEDNAVKA',E'',E'',E'',E'Pomenovanie chodov pri ich zakladaní?',E'Pomenovanie chodov pri ich zakladaní?',E'Pomenovanie chodov pri ich zakladaní?',E'',E'',E'',E'',0),
|
||||||
|
(E'alert_on_code_not_found',E'.f.',E'param',E'L',E'Zobraziť výstrahu ak sa nenájde kód?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Zobraziť výstrahu ak sa nenájde kód?',E'Zobraziť výstrahu ak sa nenájde kód?',E'',E'',E'',E'',0),
|
||||||
|
(E'continue_on_code_not_found',E'.f.',E'param',E'L',E'Pokračovať v objedávke ak sa nenašiel kód?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Pokračovať v objedávke ak sa nenašiel kód?',E'Pokračovať v objedávke ak sa nenašiel kód?',E'',E'',E'',E'',0),
|
||||||
|
(E'hk_spdob',E'"DOB"',E'param',E'C',E'Spart pre dobitie kreditu',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Spart pre dobitie kreditu',E'Spart pre dobitie kreditu',E'',E'',E'',E'uni;spart_kas;DOB',0),
|
||||||
|
(E't_bon_txt_pred_spr',E'"Pozn.:"',E'param',E'C',E'Text, ktorý sa ma tlačiť pre správou na bone. ',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Text, ktorý sa ma tlačiť pre správou na bone.',E'Text, ktorý sa ma tlačiť pre správou na bone.',E'',E'',E'',E'',0),
|
||||||
|
(E'stay_in_order_on_order_confirm_for_all_tables',E'.F.',E'param',E'L',E'Ostať v OBJ po potvrdení položiek (bežné stoly)?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Ostať v OBJ po potvrdení (bežné stoly)?',E'Ostať v OBJ po potvrdení (bežné stoly)?',E'',E'',E'',E'',0),
|
||||||
|
(E'stay_in_order_on_order_confirm_for_temp_tables',E'.F.',E'param',E'L',E'Ostať v OBJ po potvrdení položiek (jednorázové stoly)?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Ostať v OBJ po potvrdení (jednorázové stoly)?',E'Ostať v OBJ po potvrdení (jednorázové stoly)?',E'',E'',E'',E'',0),
|
||||||
|
--- tohle asi nepotřebujeme (E'order_autoconfirm_items_in_all_tables',E'.F.',E'param',E'L',E'Automaticky potvrdzovať objednané položky (bežné stoly)?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Automaticky potvrdzovať objednané položky?',E'Automaticky potvrdzovať objednané položky?',E'',E'',E'',E'',0),
|
||||||
|
--- tohle asi nepotřebujeme (E'order_autoconfirm_items_in_temp_tables',E'.F.',E'param',E'L',E'Automaticky potvrdzovať objed.položky (jednorázové stoly)?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Automaticky potvrdzovať objednané položky?',E'Automaticky potvrdzovať objednané položky?',E'',E'',E'',E'',0),
|
||||||
|
--- tohle asi nepotřebujeme (E'order_autoconfirm_items_in_bar',E'.F.',E'param',E'L',E'Automaticky potvrdzovať objednané položky (bar)?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Automaticky potvrdzovať objednané položky?',E'Automaticky potvrdzovať objednané položky?',E'',E'',E'',E'',0),
|
||||||
|
--- tohle asi nepotřebujeme (E'payment_ignore_selected_orderlines',E'.F.',E'param',E'L',E'Vzdy vyplacat cely ucet?',0,0 ,E'OBJEDNAVKA',E'',E'',E'',E'Ignorovat vybrane polozky pri vyplacani ?\ntrue = vzdy bude vyplateny cely ucet\nfalse (default) = ak su vybrane polozky, do plaby pojdu iba vybrane polozky',E'Ignorovat vybrane polozky pri vyplacani',E'Ignorovat vybrane polozky pri vyplacani',E'',E'',E'',E'',0),
|
||||||
|
(E'is_chlbar',E'.F.',E'param',E'L',E'Dotaz na cenove hladiny v bar.rezim ',0,2 ,E'OBJEDNAVKA',E'',E'',E'',E'',E'Dotaz na cenove hladiny v bar.rezim ',E'Dotaz na cenove hladiny v bar.rezim ',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- ROZNE
|
||||||
|
---
|
||||||
|
(E'quick_sync_enable_by',E'"table_id"',E'param',E'C',E'Spôsob synchronizácie pre mobilné pokladne',0,1 ,E'ROZNE',E'',E'table_id,last_updated,all ',E'',E'',E'Spôsob synchronizácie pre mobilné pokladne',E'Spôsob synchronizácie pre mobilné pokladne',E'',E'',E'',E'',0),
|
||||||
|
(E'quick_sync_for_desktop_enable_by',E'"all"',E'param',E'C',E'Spôsob synchronizácie pre desktopové pokladne',0,1 ,E'ROZNE',E'',E'table_id,last_updated,all ',E'',E'',E'Spôsob synchronizácie pre desktopové pokladne',E'Spôsob synchronizácie pre desktopové pokladne',E'',E'',E'',E'',0),
|
||||||
|
--- Presunuto do objednávky (E'is_chlbar',E'.F.',E'param',E'L',E'Dotaz na cenove hladiny v bar.rezim ',0,2 ,E'ROZNE ',E'',E'',E'',E'',E'Dotaz na cenove hladiny v bar.rezim ',E'Dotaz na cenove hladiny v bar.rezim ',E'',E'',E'',E'',0),
|
||||||
|
(E'len_nefis_platby',E'.F.',E'param',E'L',E'.T. - na kase sa daju pouzit len nefiskalne platby ',0,3,E'ROZNE ',E'',E'',E'',E'.T. - na kase sa daju pouzit len nefiskalne platby',E'.T. - na kase sa daju pouzit len nefiskalne platb ',E'.T. - na kase sa daju pouzit len nefiskalne platb ',E'.T. - na kase sa daju pouzit len nefiskalne platb ',E'.T. - na kase sa daju pouzit len nefiskalne platb ',E'.T. - na kase sa daju pouzit len nefiskalne platb ',E'',0),
|
||||||
|
(E'max_suma_kartou',E'-1',E'param',E'N',E'Maximalna suma, ktoru je mozne platit kartou. -1-neobmedzene',0,4,E'ROZNE ',E'',E'',E'',E'Maximalna suma, ktoru je mozne platit kartou. -1-neobmedzene',E'Maximalna suma, ktoru je mozne platit kartou. -1-n',E'Maximalna suma, ktoru je mozne platit kartou. -1-n',E'Maximalna suma, ktoru je mozne platit kartou. -1-n',E'Maximalna suma, ktoru je mozne platit kartou. -1-n',E'Maximalna suma, ktoru je mozne platit kartou. -1-n',E'',0),
|
||||||
|
(E'max_suma_hotovost',E'-1',E'param',E'N',E'Maximalna suma, ktoru je mozne platit v hotovosti. -1-neobme',0,5,E'ROZNE ',E'',E'',E'',E'Maximalna suma, ktoru je mozne platit v hotovosti. -1-neobmedzene',E'Maximalna suma, ktoru je mozne platit v hotovsti. ',E'Maximalna suma, ktoru je mozne platit v hotovsti. ',E'Maximalna suma, ktoru je mozne platit v hotovsti. ',E'Maximalna suma, ktoru je mozne platit v hotovsti. ',E'Maximalna suma, ktoru je mozne platit v hotovsti. ',E'',0),
|
||||||
|
(E'desktop_tables_list_columns_count',E'2',E'param',E'N',E'Počet stĺpcov v miestnosti jednorázové stoly',0,6 ,E'ROZNE',E'',E'',E'',E'',E'Počet stĺpcov v miestnosti jednorázové stoly',E'Počet stĺpcov v miestnosti jednorázové stoly',E'',E'',E'',E'',0),
|
||||||
|
(E'disable_rescale_tables',E'.f.',E'param',E'L',E'Zakázať auto zmenu veľkosti stolov na PC?',0,7 ,E'ROZNE',E'',E'',E'',E'',E'Zakázať auto zmenu veľkosti stolov na PC?',E'Zakázať auto zmenu veľkosti stolov na PC?',E'',E'',E'',E'',0),
|
||||||
|
(E'sc_saver',E'100000',E'param',E'N',E'Pocet [s] , kdy se odhlasi ',0,8,E'ROZNE ',E'',E'',E'',E'',E'Pocet [s] , kdy se odhlasi ',E'Pocet [s] , kdy se odhlasi ',E'',E'',E'',E'',0),
|
||||||
|
(E'neodpocitavat_zoz_sp',E'"SRV"',E'param',E'C',E'Zoznam spartov, kt.netreba odpocitavat zo skladov ',0,9,E'ROZNE',E'',E'',E'',E'',E'Zoznam spartov,kt.netreba odpocitavat zo skladov',E'Zoznam spartov,kt.netreba odpocitavat zo skladov',E'',E'',E'',E'multi;spart_kas;@',0),
|
||||||
|
(E'is_limspra',E'.T.',E'param',E'L',E'Povolené spracovanie limitov ',0,10,E'ROZNE',E'',E'',E'',E'',E'Povolené spracovanie limitov',E'Povolené spracovanie limitov',E'',E'',E'',E'',0),
|
||||||
|
(E'is_bazen',E'.F.',E'param',E'L',E'Bazénový režim ',0,11,E'ROZNE',E'',E'',E'',E'',E'Bazénový režim',E'Bazénový režim',E'',E'',E'',E'',0),
|
||||||
|
(E'is_filter',E'.F.',E'param',E'L',E'Rajónový režim ',0,12,E'ROZNE',E'',E'',E'',E'',E'Rajónový režim',E'Rajónový režim',E'',E'',E'',E'',0),
|
||||||
|
(E'is_filter_hide_others_tables_all',E'.F.',E'param',E'L',E'Rajónový režim - zobraz iba vlastné stoly',0,13,E'ROZNE',E'',E'',E'',E'',E'Rajónový režim - zobraz iba moje stoly',E'Rajónový režim - zobraz iba moje stoly',E'',E'',E'',E'',0),
|
||||||
|
(E'is_filter_hide_others_tables_temp',E'.F.',E'param',E'L',E'Rajónový režim - zobraz iba vlastné jednorázové stoly',0,14,E'ROZNE',E'',E'',E'',E'',E'Rajónový režim - zobraz iba moje jednoráz. stoly',E'Rajónový režim - zobraz iba moje jednoráz. stoly',E'',E'',E'',E'',0),
|
||||||
|
(E'change_orderline_ownership_with_opentable', E'.F.', E'param',E'L', E'Rajónový režim - zmena vlastnika stolu aj s obj', 0, 15, E'ROZNE', E'', E'', E'', E'', E'Rajónový režim - zmena vlastnika stolu aj s obj', E'Rajónový režim - zmena vlastnika stolu aj s obj', E'', E'', E'', E'', 0),
|
||||||
|
(E'is_dan',E'.T.',E'param',E'L',E'Platca DPH ',0,16,E'ROZNE',E'',E'',E'',E'',E'Platca DPH',E'Platca DPH',E'',E'',E'',E'',0),
|
||||||
|
(E'foodie_font',E'0',E'param',E'N',E'Veľkosť fontu v objednávke ',0,17,E'ROZNE',E'',E'',E'',E'0 - automatická voľba fontu',E'Veľkosť fontu v objednávke',E'Veľkosť fontu v objednávke',E'',E'',E'',E'',0),
|
||||||
|
(E'print_tip_confirmation',E'.f.',E'param',E'L',E'Tlačí sa potvrdenie pri zemene TIPu?',0,18 ,E'ROZNE',E'',E'',E'',E'',E'Tlačí sa potvrdenie o TIPe pri tlači účtu?',E'Tlačí sa potvrdenie pri zemene TIPu?',E'',E'',E'',E'',0),
|
||||||
|
(E'print_tip_confirmation_with_every_bill',E'.f.',E'param',E'L',E'Tlačí sa potvrdenie o TIPe pri tlači účtu? ',0,19 ,E'ROZNE',E'',E'',E'',E'',E'Tlačí sa potvrdenie o TIPe pri tlači účtu?',E'Tlačí sa potvrdenie o TIPe pri tlači účtu?',E'',E'',E'',E'',0),
|
||||||
|
(E'scrollbar_indicator_width',E'5',E'param',E'N',E'Šírka scroll barov. Klasický 5, širší 25. ',0,20 ,E'ROZNE',E'',E'',E'',E'',E'Šírka scroll barov. Klasický 5, širší 25.',E'Šírka scroll barov. Klasický 5, širší 25.',E'',E'',E'',E'',0),
|
||||||
|
(E'own_delivery_eshop_ids',E'"3"',E'param',E'C',E'Zoznam typov eshopov,kt.sa maju spravat ako vlastna donaska',1,21 ,E'ROZNE',E'',E'',E'',E'',E'Typy eshopu,kt.sa maju spravat ako vlastna donaska',E'Typy eshopu,kt.sa maju spravat ako vlastna donaska',E'',E'',E'',E'',0),
|
||||||
|
(E'own_delivery_quickpay_methods',E'""',E'param',E'C',E'Vlastna donaska - quickpay platobne metody',0,22 ,E'ROZNE',E'',E'',E'',E'Ciarkami oddelene (max 3) nazvy platieb z druhy_pl, kt. sa pouziju ako quickpay pir vlastnej donaske',E'Donaska - quickpay platobne metody',E'Donaska - quickpay platobne metody',E'',E'',E'',E'',0),
|
||||||
|
(E'own_delivery_columns',E'""',E'param',E'C',E'Vlastna donaska - stlpce v zozname objednavok',0,23 ,E'ROZNE',E'',E'',E'',E'Ciarkami oddelene oznacenia stlpcov, ktore maju byt v zozname objednavok:\n\ncustomer_name - meno zakaznika\ncustomer_phone - telefonne cislo zakaznika\ncustomer_email - e-mail zakaznika\naddress - adresa\naddress_with_customer_name - meno zakaznika spolu s adresou\naddress_with_customer_name_last - adresa spolu s menom zakaznika na konci\nnotes - vsetky poznamky oddelene znakom ";"\nnote_address - poznamka priradena k adrese\nnote_customer - poznamka priradena k zakaznikovi\nnote_order_all - vsetky poznamky priradene k obejdnavke oddelene znakom ";"\nnote_order_1 - prva poznamka k objednavke\nnote_order_2 - druha poznamka k objednavke\norder_price - cena objedanvky\norder_date - datum objednavky\norder_datetime - datum a cas objednavky\norder_status - stav objednavky\norder_author - casnik, ktory vytvoril objednavku\n',E'Donaska - stlpce v zozname objednavok',E'Donaska - stlpce v zozname objednavok',E'',E'',E'',E'',0),
|
||||||
|
(E'own_delivery_cp_search_term_to_new_user_phone',E'.F.',E'param',E'L',E'Vlastna donaska - kopir. hladany text do noveho zakaznika?',0,24 ,E'ROZNE',E'',E'',E'',E'Ci sa ma text, ktory obsluha zadala pri hladani zakaznika prekopirovat do policka telefon ak nenajdu zakaznika a kliknu ze chcu zalozit noveho (aby to nemuseli vypisovat znovu)',E'Donaska - kopir. hladany text do noveho zakaznika?',E'Donaska - kopir. hladany text do noveho zakaznika?',E'',E'',E'',E'',0),
|
||||||
|
(E'allow_duplicates_in_category_contents',E'.T.',E'param',E'L',E'Povolit viacero rovnakych klapiek na jednej stranke?',0,25 ,E'ROZNE',E'',E'',E'',E'',E'Povolit viac rovnakych klapiek na jednej stranke?',E'Povolit viac rovnakych klapiek na jednej stranke?',E'',E'',E'',E'',0),
|
||||||
|
(E'obj_zobraz_plu_keyb',E'.F.',E'param',E'L',E'Namiesto klapiek zobrazovat PLU keyborad ',0,26,E'ROZNE ',E'',E'',E'',E'',E'Namiesto klapiek zobrazovat PLU keyborad ',E'',E'Namiesto klapiek zobrazovat PLU keyborad ',E'Namiesto klapiek zobrazovat PLU keyborad ',E'Namiesto klapiek zobrazovat PLU keyborad ',E'',0),
|
||||||
|
(E'men_cen_man',E'""',E'param',E'C',E'Zámena managerov pri vytváraní cenníka pokladne ',0,27,E'ROZNE ' ,E'',E'',E'',E'',E'Zámena managerov pri vytváraní cenníka pokladne ',E'Zámena managerov pri vytváraní cenníka pokladne ',E'',E'',E'',E'',0),
|
||||||
|
(E'men_cen_prn',E'""',E'param',E'C',E'Zámena tlačiarní pri vytváraní cenníka pokladne ',0,28,E'ROZNE ' ,E'',E'',E'',E'',E'Zámena tlačiarní pri vytváraní cenníka pokladne ',E'Zámena tlačiarní pri vytváraní cenníka pokladne ',E'',E'',E'',E'',0),
|
||||||
|
(E'ignore_limit_items',E'.F.',E'param',E'L',E'Majú sa ignorovať limity na mobiloch? ',0,0 ,E'ROZNE',E'',E'',E'',E'',E'Majú sa ignorovať limity na mobiloch?',E'Majú sa ignorovať limity na mobiloch?',E'',E'',E'',E'',0),
|
||||||
|
(E'mobilne_terminaly',E'0',E'param',E'N',E'Počet predplatených mobilných terminálov ',1,0 ,E'ROZNE',E'',E'',E'',E'',E'Počet predplatených mobilných terminálov',E'Počet predplatených mobilných terminálov',E'',E'',E'',E'',0),
|
||||||
|
(E'show_plu_on_item', E'.F.',E'param', E'L',E'Zobraziť na klapke jej PLU?',0,29,E'ROZNE',E'',E'',E'',E'true = na klapke bude zobrazené aj PLU položky priradenej k danej klapke\nfalse - na klapke nebude zobrazené plu (deafult)',E'Zobraziť na klapke jej PLU?',E'Zobraziť na klapke jej PLU?',E'',E'',E'',E'',0),
|
||||||
|
(E'items_search_order_by',E'"name"',E'param',E'C',E'Vyhladavanie poloziek - Radenie vysledkov podla...',0,30 ,E'ROZNE',E'',E'name,price,plu',E'',E'name = zoradovanie podla nazvu\nprice = zoradovanie podla ceny\nplu = zoradovanie podla PLU',E'Vyhladavanie poloziek - Radenie vysledkov podla...',E'Vyhladavanie poloziek - Radenie vysledkov podla...',E'',E'',E'',E'',0),
|
||||||
|
(E'items_search_order_direction',E'"asc"',E'param',E'C',E'Vyhladavanie poloziek - Smer radenia vysledkov',0,31 ,E'ROZNE',E'',E'asc,desc',E'',E'asc = zoradovanie vzostupne (a->z, 0->9)\ndesc = zoradovanie zostupne (z->a, 9->0)',E'Vyhladavanie poloziek - Smer radenia vysledkov',E'Vyhladavanie poloziek - Smer radenia vysledkov',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- UCET
|
||||||
|
---
|
||||||
|
(E'card_pay_no_term',E'"qweqwe"',E'param',E'C',E'Platba pre kartu bez terminálu ',0,1 ,E'UCET',E'',E'',E'',E'',E'Platba pre kartu bez terminálu',E'',E'',E'',E'',E'uni;druhy_pl;qweqwe',0),
|
||||||
|
(E'bar_pay_in_cash',E'"Hotove"',E'param',E'C',E'Platba pre bar v hotovosti ',0,2 ,E'UCET',E'',E'',E'',E'',E'Platba pre bar v hotovosti',E'Platba pre bar v hotovosti',E'',E'',E'',E'uni;druhy_pl;Hotove',0),
|
||||||
|
(E'is_platdel',E'.T.',E'param',E'L',E'Pouzivat deleni plateb ',0,3 ,E'UCET ',E'',E'',E'',E'',E'Pouzivat deleni plateb ',E'Pouzivat deleni plateb ',E'',E'',E'',E'',0),
|
||||||
|
(E'zkr_mena',E'CZK',E'param',E'C',E'Zkratka oznacujici menu ',0,4 ,E'UCET ',E'',E'',E'',E' ',E'Zkratka oznacujici menu ',E'Zkratka oznacujici menu ',E' ',E' ',E' ',E' ',0),
|
||||||
|
(E'discount_mode',E'"bill"',E'param',E'C',E'Spôsob vypisovania zľavy na účte ',0,5 ,E'UCET ',E'',E'bill,item ',E'',E' ',E'Spôsob vypisovania zľavy na účte',E'Spôsob vypisovania zľavy na účte',E' ',E' ',E' ',E' ',0),
|
||||||
|
(E'is_zaok50',E'.F.',E'param',E'L',E'Pouzivat zaokrohlovani na padiky ',0,6 ,E'UCET ',E'',E'',E'',E'',E'Pouzivat zaokrohlovani na padiky ',E'Pouzivat zaokrohlovani na padiky ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_zaokjho',E'.F.',E'param',E'L',E'Zaokrouhlit je hotovost ',0,7 ,E'UCET ',E'',E'',E'is_zaok50;=;.T. ',E'',E'Zaokrouhlit je hotovost ',E'Zaokrouhlit je hotovost ',E'',E'',E'',E'',0),
|
||||||
|
(E'terminal_storno',E'3',E'param',E'N',E'Typ storna pre terminály ',0,8 ,E'UCET',E'',E'0,1,2,3 ',E'',E'0 - peniaze sa vracajú v hotovosti\n1 - peniaze sa vracajú cez terminál na kartu\n2 - storno je zakázané\n3 - storno bez komunikácie s terminálom (treba nastaviť platbu do CARD_PAY_NO_TERM)',E'Typ storna pre terminály',E'Typ storna pre terminály',E'',E'',E'',E'',0),
|
||||||
|
(E'is_subtot',E'.F.',E'param',E'L',E'Má sa na nefiškálne bločky tlačiť jednotková cena? ',0,9 ,E'UCET',E'',E'',E'',E'',E'Má sa na nefiškálne bločky tlačiť jednotková cena?',E'Má sa na nefiškálne bločky tlačiť jednotková cena?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_couvert',E'.F.',E'param',E'L',E'Má sa pri platbe zadať počet hostí? ',0,10,E'UCET',E'',E'',E'',E'',E'Má sa pri platbe zadať počet hostí?',E'Má sa pri platbe zadať počet hostí?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_couvert_force',E'.F.',E'param',E'L',E'Má v payscreene zobraziť okno na zadanie počtu hostí?',0,11,E'UCET',E'',E'',E'',E'',E'V payscreene zobraziť okno na zadanie počtu hostí',E'V payscreene zobraziť okno na zadanie počtu hostí',E'',E'',E'',E'',0),
|
||||||
|
(E't_fast_polozky',E'.T.',E'param',E'L',E'Tlačiť položky FST menu s nulovou cenou? ',0,12,E'UCET',E'',E'',E'',E'',E'Tlacit polozky FST menu s nulovou cenou?',E'Tlacit polozky FST menu s nulovou cenou?',E'',E'',E'',E'',0),
|
||||||
|
(E'fst_ako_spocit_na_uc',E'1',E'param',E'N',E'Ako spočítavať fast food menu na účte? ',0,13,E'UCET ',E'',E'0,1,2 ',E'',E'0 - nespočítavať\n1 - spočítať menu s rovnakými položkami\n2 - spočítať rovnaké menu bez ohľadu na vybrané položky ',E'Spočítavať fast food menu na účte? ',E'Spočítavať fast food menu na účte? ',E'Spočítavať fast food menu na účte? ',E'',E'',E'',0),
|
||||||
|
(E'is_tipdot',E'.t.',E'param',E'L',E'Je povolen TIP ',0,14,E'UCET ',E'',E'',E'',E'',E'Je povolen TIP ',E'Je povolen TIP ',E'',E'',E'',E'',0),
|
||||||
|
(E'tip_dph',E'1.0',E'param',E'N',E'Sadzba DPH pre TIP ',0,15,E'UCET',E'',E'',E'',E'',E'',E'',E'',E'',E'',E'',0),
|
||||||
|
(E'is_tipvzdy',E'.F.',E'param',E'L',E'TIP a TOTAL vždy (nie len s kreditkami) ',0,16 ,E'UCET',E'',E'',E'',E'',E'TIP a TOTAL vzdy (ne jen u kred)',E'TIP a TOTAL vzdy (ne jen u kred)',E'',E'',E'',E'',0),
|
||||||
|
(E'nkop_edit',E'.f.',E'param',E'L',E'Editovateľný počet kópií účtenky ',0,17,E'UCET',E'',E'',E'',E'',E'Editovateľný počet kópií účtenky',E'Editovateľný počet kópií účtenky',E'',E'',E'',E'',0),
|
||||||
|
(E'nkop_edit_quickpay',E'.f.',E'param',E'L',E'Okno na zadanie počtu kópii v quicklpay?',0,18,E'UCET',E'',E'',E'',E'',E'Okno na zadanie počtu kópii v quicklpay?',E'Okno na zadanie počtu kópii v quicklpay?',E'',E'',E'',E'',0),
|
||||||
|
(E'require_cancel_reason',E'.f.',E'param',E'L',E'Vyžadovať dôvod storna?',0,19 ,E'UCET',E'',E'',E'',E'',E'Vyžadovať dôvod storna?',E'Vyžadovať dôvod storna?',E'',E'',E'',E'',0),
|
||||||
|
(E'is_pockoppreducet',E'.F.',E'param',E'L',E'Otazka na poc. kopii pri preducte. Nutne nastavit nkopkre ',0,20,E'UCET ',E'',E'',E'',E'',E'Otazka na poc. kopii pri preducte. Nutne nastavit ',E'Otazka na poc. kopii pri preducte. Nutne nastavit ',E'',E'',E'',E'',0),
|
||||||
|
(E'print_bon_on_cancel',E'.T.',E'param',E'L',E'Tlačiť storno objednávky pri storne účtu? ',0,21,E'UCET',E'',E'',E'',E'',E'Tlačiť storno objednávky pri storne účtu?',E'Tlačiť storno objednávky pri storne účtu?',E'',E'',E'',E'',0),
|
||||||
|
(E't_uc_info',E'.f.',E'param',E'L',E'Tlačiť na účty info v cudzej mene?',0,22 ,E'UCET',E'',E'',E'',E'',E'Tlačiť na účty info v cudzej mene?',E'Tlačiť na účty info v cudzej mene?',E'',E'',E'',E'',0),
|
||||||
|
(E't_uc_mena',E'"EUR"',E'param',E'C',E'Skratka info meny na účty',0,23 ,E'UCET',E'',E'',E'',E'',E'Skratka info meny na účty',E'Skratka info meny na účty',E'',E'',E'',E'',0),
|
||||||
|
(E't_uc_npr',E'"@"',E'param',E'C',E'Sparty, ktoré sa netlačia na úcet (ak suma=0)',0,24 ,E'UCET',E'',E'',E'',E'',E'Sparty, ktoré sa netlačia na úcet (ak suma=0)',E'Sparty, ktoré sa netlačia na úcet (ak suma=0)',E'',E'',E'',E'',0),
|
||||||
|
(E'update_vat_on_payment_until',E'"2025-02-02"',E'param',E'C',E'Dátum do kedy robiť zmenu dph pred platbou.',0,25 ,E'UCET',E'',E'',E'',E'',E'Dátum do kedy robiť zmenu dph pred platbou.',E'Dátum do kedy robiť zmenu dph pred platbou.',E'',E'',E'',E'',0),
|
||||||
|
(E'show_payment_after_pay',E'.f.',E'param',E'L',E'Zobraziť okno s výdavkom ?',0,26 ,E'UCET',E'',E'',E'',E'',E'',E'Zobraziť okno s výdavkom ?',E'',E'',E'',E'',0),
|
||||||
|
(E'reauth_before_cancel',E'.F.',E'param',E'L',E'Pýtať si heslo pred stornom?',0,27 ,E'UCET',E'',E'',E'',E'Pýtať si heslo pred stornom?',E'Pýtať si heslo pred stornom?',E'Pýtať si heslo pred stornom?',E'',E'',E'',E'',0),
|
||||||
|
(E'reauth_before_cancel_attribute_sales_to_new',E'.T.',E'param',E'L',E'Storno na novo prihláseného čašníka?',0,28 ,E'UCET',E'',E'',E'',E'Storno na novo prihláseného čašníka?',E'Storno na novo prihláseného čašníka?',E'Storno na novo prihláseného čašníka?',E'',E'',E'',E'',0),
|
||||||
|
(E'reauth_before_payment',E'.F.',E'param',E'L',E'Pýtať si heslo pred platbou?',0,29 ,E'UCET',E'',E'',E'',E'Pýtať si heslo pred platbou?',E'Pýtať si heslo pred platbou?',E'Pýtať si heslo pred platbou?',E'',E'',E'',E'',0),
|
||||||
|
(E'reauth_before_payment_attribute_sales_to_new',E'.T.',E'param',E'L',E'Účet na novo prihláseného čašníka?',0,30 ,E'UCET',E'',E'',E'',E'Účet na novo prihláseného čašníka?',E'Účet na novo prihláseného čašníka?',E'Účet na novo prihláseného čašníka?',E'',E'',E'',E'',0),
|
||||||
|
(E'reprint_current_closure_bill_via',E'"fiskal"',E'param',E'C',E'Kópiu účtu z aktuálnej uzávierky tlačiť cez?',0,31 ,E'UCET',E'',E'fiskal,foodie',E'',E'',E'Kópiu účtu z aktuálnej uzávierky tlačiť cez?',E'Kópiu účtu z aktuálnej uzávierky tlačiť cez?',E'',E'',E'',E'',0),
|
||||||
|
(E'reprint_past_closure_bill_via',E'"foodie"',E'param',E'C',E'Kópiu účtu zo starej uzávierky tlačiť cez?',0,32 ,E'UCET',E'',E'fiskal,foodie',E'',E'',E'Kópiu účtu zo starej uzávierky tlačiť cez?',E'Kópiu účtu zo starej uzávierky tlačiť cez?',E'',E'',E'',E'',0),
|
||||||
|
(E'print_cancel_bill_always_on_prnno',E'""',E'param',E'C',E'Nefiškálne storno účty tlačiť vždy na tlačiareň',0,33 ,E'UCET',E'',E'',E'',E'',E'Nefiškálne storno účty tlačiť vždy na prn_no',E'Nefiškálne storno účty tlačiť vždy na prn_no',E'',E'',E'',E'',0),
|
||||||
|
(E'print_reprint_bill_always_on_prnno',E'""',E'param',E'C',E'Kópiu nefiškálnych účtov tlačiť vždy na tlačiareň',0,34 ,E'UCET',E'',E'',E'',E'',E'Kópiu nefiškálnych účtov tlačiť vždy na prn_no',E'Kópiu nefiškálnych účtov tlačiť vždy na prn_no',E'',E'',E'',E'',0),
|
||||||
|
(E'payment_attribute_sales_to_author',E'.F.',E'param',E'L',E'Účet na časníka ktorý nablokoval položky?',0,35 ,E'UCET',E'',E'',E'',E'Účet na časníka ktorý nablokoval položky?',E'Účet na časníka ktorý nablokoval položky?',E'Účet na časníka ktorý nablokoval položky?',E'',E'',E'',E'',0),
|
||||||
|
(E'nonfiscal_bill_dont_cancel_on_print_error',E'.T.',E'param',E'L',E'Nerob auto storo pri chybe tlaci nefiskal. uctu?',0,36 ,E'UCET',E'',E'',E'',E'Ak nastala chyba tlače nefiškálneho dokladu,\nmá sa pokračovať bez robenia automatického storna?\nTrue = ano, nerob automaticke storno\nFalse - urob automaticke storno a vrat polozky na stol',E'Nerob auto storo pri chybe tlaci nefiskal. uctu?',E'Nerob auto storo pri chybe tlaci nefiskal. uctu?',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- UZAVIERKA
|
||||||
|
---
|
||||||
|
(E't_uz_ucet',E'.F.',E'param',E'L',E'report účtů v uzávěrce? ',0,13,E'UZAVIERKA' ,E'',E'',E'',E'',E'report účtů v uzávěrce? ',E'report účtů v uzávěrce? ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_trzdr',E'.F.',E'param',E'L',E'rozdělení tržeb dle druhů ',0,14,E'UZAVIERKA' ,E'',E'',E'',E'',E'rozdělení tržeb dle druhů ',E'rozdělení tržeb dle druhů ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_harek',E'.F.',E'param',E'L',E'Je harek v uzaverce? ',0,15,E'UZAVIERKA' ,E'',E'',E'',E'Vytlacit na uzavierke zoznam predanych poloziek?',E'Je harek v uzaverce? ',E'Je harek v uzaverce? ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_dph',E'.F.',E'param',E'L',E'Uzav. tisk po DPH ',0,18,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uzav. tisk po DPH ',E'Uzav. tisk po DPH ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_man',E'.T.',E'param',E'L',E'uzav. tisk po managerech ',0,19,E'UZAVIERKA' ,E'',E'',E'',E'',E'uzav. tisk po managerech ',E'uzav. tisk po managerech ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_cenhl',E'.T.',E'param',E'L',E'Uzav. tisk po cenovych hladinach ',0,20,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uzav. tisk po cenovych hladinach ',E'Uzav. tisk po cenovych hladinach ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_ras',E'.F.',E'param',E'L',E'Tisky po rastrech ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisky po rastrech ',E'Tisky po rastrech ',E'',E'',E'',E'',0),
|
||||||
|
(E'zrc_sp_l',E'"\'@\'"',E'param',E'C',E'Sparty, ktere se tisknou na zrcadlo ',0,45,E'UZAVIERKA' ,E'',E'',E'',E'',E'Sparty, ktere se tisknou na zrcadlo ',E'Sparty, ktere se tisknou na zrcadlo ',E'',E'',E'',E'multi;spart_kas;@',0),
|
||||||
|
(E't_uz_zrc',E'.F.',E'param',E'L',E'Uzav. tisk zrcadla ',0,22,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uzav. tisk zrcadla ',E'Uzav. tisk zrcadla ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_man_dph',E'.F.',E'param',E'L',E'Uzav. tisk po managerech a DPH ',0,19,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uzav. tisk po managerech a DPH ',E'Uzav. tisk po managerech a DPH ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_hjen',E'.F.',E'param',E'L',E'Jen hotovost bez sumy celkem ',0,24,E'UZAVIERKA' ,E'',E'',E'',E'',E'Jen hotovost bez sumy celkem ',E'Jen hotovost bez sumy celkem ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_spcis',E'.F.',E'param',E'L',E'Uz.tisk po spartech a cisnicich ',0,25,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uz.tisk po spartech a cisnicich ',E'Uz.tisk po spartech a cisnicich ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_dphsm',E'.F.',E'param',E'L',E'Tisk sumare DPH ',0,26,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk sumare DPH ',E'Tisk sumare DPH ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_puctu',E'.F.',E'param',E'L',E'Tisk poctu uctu v uzaverce ',0,27,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk poctu uctu v uzaverce ',E'Tisk poctu uctu v uzaverce ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_stzur',E'.F.',E'param',E'L',E'Tisk zurnalu storen v uzaverce ',0,28,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk zurnalu storen v uzaverce ',E'Tisk zurnalu storen v uzaverce ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uzcis_pl',E'.T.',E'param',E'L',E'Tisk i bezhot.plateb v uzav cisniku ',0,29,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk i bezhot.plateb v uzav cisniku ',E'Tisk i bezhot.plateb v uzav cisniku ',E'',E'',E'',E'',0),
|
||||||
|
(E'har_spart',E'""',E'param',E'C',E'Sparty, kt.maju byt v harku na uzav ',0,16,E'UZAVIERKA' ,E'',E'',E't_uz_harek;=;.T. ',E'',E'Sparty, kt.maju byt v harku na uzav ',E'Sparty, kt.maju byt v harku na uzav ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_casni',E'.T.',E'param',E'L',E'Tlacit uzavierku po casnikoch ',0,30,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlacit uzavierku po casnikoch ',E'Tlacit uzavierku po casnikoch ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_cshot',E'.T.',E'param',E'L',E'Tlacit uzavierku po casnikoch hotov ',0,31,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlacit uzavierku po casnikoch hotov ',E'Tlacit uzavierku po casnikoch hotov ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_stmin',E'.F.',E'param',E'L',E'Tisk storen v minulych uzaverkach ',0,32,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk storen v minulych uzaverkach ',E'Tisk storen v minulych uzaverkach ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_ptran',E'.F.',E'param',E'L',E'Pocet transakci (transakce=novy stu ',1,33,E'UZAVIERKA' ,E'',E'',E'',E'',E'Pocet transakci (transakce=novy stu ',E'Pocet transakci (transakce=novy stu ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_vicek',E'.F.',E'param',E'L',E'Tisk vicenasobne pouzitych karet v ',0,34,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tisk vicenasobne pouzitych karet v ',E'Tisk vicenasobne pouzitych karet v ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_kombi',E'.F.',E'param',E'L',E'Tlacit UZ podla man,druh_pl,dan ',0,35,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlacit UZ podla man,druh_pl,dan ',E'Tlacit UZ podla man,druh_pl,dan ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uzcis_ma',E'.F.',E'param',E'L',E'Tlac podla managerov u uz. casnikov ',0,36,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlac podla managerov u uz. casnikov ',E'Tlac podla managerov u uz. casnikov ',E'',E'',E'',E'',0),
|
||||||
|
--- není to duplicta k men_cen_man (E'men_sp_man',E'""',E'param',E'C',E'Zmena exportu do cenara pri uzavierke pokladne ',0,4 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'Zmena exportu do cenara pri uzavierke pokladne ',E'Zmena exportu do cenara pri uzavierke pokladne ',E'',E'',E'',E'',0),
|
||||||
|
(E'is_denstat',E'.T.',E'param',E'L',E'.T. - robi sa denne statisticka uzavierka, .F. - nerobi sa ',0,2 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'.T. - robi sa denne statisticka uzavierka, .F. - n',E'.T. - robi sa denne statisticka uzavierka, .F. - n',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_spdph',E'.F.',E'param',E'L',E'Uz.tisk po spartech a sadzbach DPH ',0,37,E'UZAVIERKA' ,E'',E'',E'',E'',E'Uz.tisk po spartech a sadzbach DPH ',E'Uz.tisk po spartech a sadzbach DPH ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_poh_drpl',E'.F.',E'param',E'L',E'Tlačiť na uzávierke rozdelenie poľadavok podľa cas. a drpl. ',0,38,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlačiť na uzávierke rozdelenie poľadavok podľa cas',E'Tlačiť na uzávierke rozdelenie poľadavok podľa cas',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_vkl_drpl',E'.F.',E'param',E'L',E'Tlačiť na uzávierke rozdelenie vklad/vyber podľa cas. a plat',0,39,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlačiť na uzávierke rozdelenie vklad/vyber podľa c',E'Tlačiť na uzávierke rozdelenie vklad/vyber podľa c',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_trz_vkl_drpl',E'.F.',E'param',E'L',E'Tlačiť na uzáv.rozdel. trržby+vklad/vyber podľa cas. a plat.',0,40,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlačiť na uzáv.rozdel. trržby+vklad/vyber podľa ca',E'Tlačiť na uzáv.rozdel. trržby+vklad/vyber podľa ca',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_vklad_vyber',E'.F.',E'param',E'L',E'Tlačiť na uzávierke zoznam vkladov a vyberov ',0,41,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlačiť na uzávierke zoznam vkladov a vyberov ',E'Tlačiť na uzávierke zoznam vkladov a vyberov ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_tlacpredajalko',E'.F.',E'param',E'L',E'Pri uzav. tlaci predaj alokoholu ',0,42,E'UZAVIERKA' ,E'',E'',E'',E'',E'Pri uzav. tlaci pradj alokoholu ',E'Pri uzav. tlaci pradj alokoholu ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_editpredajalko',E'.F.',E'param',E'L',E'Pri uzav. zobrazi formular na zadavanie/opravu predaj alka ',0,43,E'UZAVIERKA' ,E'',E'',E'',E'',E'Pri uzav. zobrazi formular na zadavanie/opravu pre',E'Pri uzav. zobrazi formular na zadavanie/opravu pre',E'',E'',E'',E'',0),
|
||||||
|
(E'spotreba_po_druhoch',E'.T.',E'param',E'L',E'Report spotreby grupovat po druhoch ',0,48,E'UZAVIERKA' ,E'',E'',E'',E'',E'spotreba_po_druhoch ',E'spotreba_po_druhoch ',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_objed',E'.F.',E'param',E'L',E'Tlač vytvorenych objednavok v uzavierke ',0,44,E'UZAVIERKA' ,E'',E'',E'',E'Tlač vytvorenych objednavok v uzavierke. Polozky, ktore maju k_odpoctu "C".',E'Tlač vytvorenych objednavok v uzavierke ',E'Tlač vytvorenych objednavok v uzavierke ',E'Tlač vytvorenych objednavok v uzavierke ',E'Tlač vytvorenych objednavok v uzavierke',E'Tlač vytvorenych objednavok v uzavierke',E'',0),
|
||||||
|
(E't_uz_drpl',E'.T.',E'param',E'L',E'Tlač tržby po druhoch platby ',0,45,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač tržby po druhoch platby',E'Tlač tržby po druhoch platby',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_odovzdanie',E'.T.',E'param',E'L',E'Tlač sumy na odovzdanie na uzávierku ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač sumy na odovzdanie na uzávierku',E'Tlač sumy na odovzdanie na uzávierku',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_fisk_platby',E'.T.',E'param',E'L',E'Tlač reportu po fiškálnych platbách ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač reportu po fiškálnych platbách',E'Tlač reportu po fiškálnych platbách',E'',E'',E'',E'',0),
|
||||||
|
(E'uzav_odvod',E'"0"',E'param',E'C',E'Výber pri uzávierke ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'0 - nerobiť výber\n1 - automaticky vybrať celú tržbu + vklady pre nastavené platidlá\n2 - zobraziť obsluhe možnosť zadať prevod do nového dňa, aby ráno nemuseli robiť vklad\n',E'Výber pri uzávierke',E'Výber pri uzávierke',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_drpldan',E'.T.',E'param',E'L',E'Tlač reportu po platbách a daniach na uzávierku ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač reportu po platbách a daniach na uzávierku',E'Tlač reportu po platbách a daniach na uzávierku',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_drplfisdan',E'.T.',E'param',E'L',E'Tlač reportu po fiškálnych platbách a daniach ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač reportu po fiškálnych platbách a daniach',E'Tlač reportu po fiškálnych platbách a daniach',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_dph_fis',E'.F.',E'param',E'L',E'Tlač reportu po DPH - fiškálne platby ',0,21,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač reportu po DPH - fiškálne platby',E'Tlač reportu po DPH - fiškálne platby',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_terminal',E'.f.',E'param',E'L',E'Platby po termináloch v uzávierke ',0,1 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'Platby po termináloch v uzávierke',E'Platby po termináloch v uzávierke',E'',E'',E'',E'',0),
|
||||||
|
(E'is_uzostul',E'.t.',E'param',E'L',E'Je povolená uzávierka s otvorenými stolmi? ',0,1 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'Je povolená uzávierka s otvorenými stolmi?',E'Je povolená uzávierka s otvorenými stolmi?',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_mena',E'.f.',E'param',E'L',E'Tlač reportu po menách na uzávierke',0,46 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač reportu po menách na uzávierke',E'Tlač reportu po menách na uzávierke',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_stoly',E'.f.',E'param',E'L',E'Tlač otvorených stolov na uzávierke',0,46 ,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač otvorených stolov na uzávierke',E'Tlač otvorených stolov na uzávierke',E'',E'',E'',E'',0),
|
||||||
|
(E't_uz_puctu_cas',E'.F.',E'param',E'L',E'Tlač počtu účtov po čašníkoch',0,27,E'UZAVIERKA' ,E'',E'',E'',E'',E'Tlač počtu účtov po čašníkoch',E'Tlač počtu účtov po čašníkoch',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- PERIFERIE (DISPLAY, PRICECHECKER, RECYKLOMAT, SUFLIK, VAHY)
|
||||||
|
---
|
||||||
|
--- DISPLAY
|
||||||
|
(E'external_display',E'.f.',E'param',E'L',E'Používa sa externý display?',0,1 ,E'DISPLAY',E'',E'',E'',E'',E'',E'Používa sa externý display?',E'',E'',E'',E'',0),
|
||||||
|
(E'external_display_thankyou_message',E'"Ďakujeme za Váš nákup"',E'param',E'C',E'Sprava dakujeme',0,2 ,E'DISPLAY',E'',E'',E'',E'',E'',E'Sprava dakujeme',E'',E'',E'',E'',0),
|
||||||
|
(E'external_display_default_message',E'"Vitajte"',E'param',E'C',E'Uvodna sprava',0,3 ,E'DISPLAY',E'',E'',E'',E'',E'',E'Uvodna sprava',E'',E'',E'',E'',0),
|
||||||
|
(E'external_display_logout_message',E'"Pokladňa mimo prevádzku"',E'param',E'C',E'Správa pri odhlásenej pokladni',0,4 ,E'DISPLAY',E'',E'',E'',E'',E'',E'Správa pri odhlásenej pokladni',E'',E'',E'',E'',0),
|
||||||
|
(E'external_display_show_total_on_table_open',E'.t.',E'param',E'L',E'Vypis iba sumu total, alebo vsetky polozky',0,5 ,E'DISPLAY',E'',E'',E'',E'',E'',E'Vypis iba sumu total, alebo vsetky polozky',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
--- PRICECHECKER
|
||||||
|
(E'pricechecker_template_logo_url',E'""',E'param',E'C',E'URL adresa k obrazku s logom prevadzky',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'URL adresa k obrazku s logom prevadzky',E'URL adresa k obrazku s logom prevadzky',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_background_image',E'""',E'param',E'C',E'URL adresa k obrazku, ktory sa pouzije ako pozadie',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'URL adresa k obrazku, ktory sa pouzije ako pozadie',E'URL adresa k obrazku, ktory sa pouzije ako pozadie',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_background_color',E'"#ffffff"',E'param',E'C',E'Farba pozadia v RGB hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba pozadia v RGB hex formate',E'Farba pozadia v RGB hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_text_background_color',E'"#ffffff"',E'param',E'C',E'Farba pozadia text.elementov v RGB hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba pozadia text.elementov v RGB hex formate',E'Farba pozadia text.elementov v RGB hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_text_background_alpha',E'0.75',E'param',E'N',E'Priehladnost pozadia textovych elementov',0,23 ,E'PriceCheck',E'',E'',E'',E'Priehladnost pozadia textovych elementov v rozmedzi 0-1 (desatinne cislo) - 0 je uplne priehladne, 1 - uplne nepriehladne',E'Priehladnost pozadia textovych elementov',E'Priehladnost pozadia textovych elementov',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_text_border_color',E'"#000000"',E'param',E'C',E'Farba oramovania text.elementov v RGB hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba oramovania text.elementov v RGB hex formate',E'Farba oramovania text.elementov v RGB hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_text_color',E'"#000000"',E'param',E'C',E'Farba textu v RBG hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba textu v RBG hex formate',E'Farba textu v RBG hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_element_background_color',E'"#ffffff"',E'param',E'C',E'Farba pozadia netext.elementov v RGB hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba pozadia netext.elementov v RGB hex formate',E'Farba pozadia netext.elementov v RGB hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_element_foreground_color',E'"#000000"',E'param',E'C',E'Farba netextovych elementov v RBG hex formate',0,23 ,E'PriceCheck',E'',E'',E'',E'',E'Farba netextovych elementov v RBG hex formate',E'Farba netextovych elementov v RBG hex formate',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_template_reset_timeout',E'10',E'param',E'N',E'Čas zobrazenia informácie o cene produktu',0,23 ,E'PriceCheck',E'',E'',E'',E'Cas v sekundach, po ktorom sa vrati pricechecker z informacie o cene produktu na hlavny screen (i.e. kolko je zobrazena informacia o cene nacitaneho produktu)',E'Čas zobrazenia informácie o cene produktu',E'Čas zobrazenia informácie o cene produktu',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_default_pricelevel',E'""',E'param',E'C',E'Cenova hladina, v ktorej ukazuje pricechecker ceny',0,23 ,E'PriceCheck',E'',E'',E'',E'default hodnota - nenastavene, alebo prazdny string. ak je prazdny string, pouzije pricechecker automaticky cenovu hladinu definovanu v K32.def_cenhla',E'Cenova hladina v ktorej ukazuje pricechecker ceny',E'Cenova hladina v ktorej ukazuje pricechecker ceny',E'',E'',E'',E'',0),
|
||||||
|
(E'pricechecker_allowed_pricelevels',E'""',E'param',E'C',E'Cenové hladiny, ktoré má pricechecker zobrazovať',0,23 ,E'PriceCheck',E'',E'',E'',E'príklad hodnôt: {"1": "Zakladna cena", "3": "Akciova cena", "4": "Zamestnanecka cena"}',E'Cenové hladiny, ktoré má pricechecker zobrazovať',E'Cenové hladiny, ktoré má pricechecker zobrazovať',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
--- RECYKLOMAT
|
||||||
|
(E'recyclomat',E'.f.',E'param',E'L',E'Povoliť recyklomat',0,0,E'RECYKLOMAT',E'',E'',E'',E'',E'',E'Povoliť recyklomat',E'',E'',E'',E'',0),
|
||||||
|
(E'recyclomat_code_length',E'0',E'param',E'N',E'Dĺžka recyklomat kódu',0,0,E'RECYKLOMAT',E'',E'',E'',E'',E'Dĺžka recyklomat kódu',E'Dĺžka recyklomat kódu',E'',E'',E'',E'',0),
|
||||||
|
(E'recyclomat_code_prefix',E'"33"',E'param',E'C',E'Prefix recyklomat kódu (hodnoty 01-99)',0,0,E'RECYKLOMAT',E'',E'',E'',E'',E'Prefix recyklomat kódu (hodnoty 01-99)',E'Prefix recyklomat kódu (hodnoty 01-99)',E'',E'',E'',E'',0),
|
||||||
|
(E'recyclomat_article_id',E'0',E'param',E'N',E'ID polozky, ktora ma byt nablokovana',0,0,E'RECYKLOMAT',E'',E'',E'',E'',E'ID polozky, ktora ma byt nablokovana',E'ID polozky, ktora ma byt nablokovana',E'',E'',E'',E'',0),
|
||||||
|
(E'recyclomat_allowed_ids','"xxx"',E'param',E'C',E'ID automatov oddelene bodkociarkou',0,0,E'RECYKLOMAT',E'',E'',E'',E'',E'ID automatov na prevadzke oddelene bodkociarkou',E'ID automatov na prevadzke oddelene bodkociarkou',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
--- SUFLIK
|
||||||
|
(E'sup_op',E'0',E'param',E'N',E'Suplik= 0 neni, 1..4 Com, 5 kartou ',0,1 ,E'SUFLIK ',E'',E'',E'',E'',E'Suplik= 0 neni, 1..4 Com, 5 kartou ',E'Suplik= 0 neni, 1..4 Com, 5 kartou ',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
--- VAHY
|
||||||
|
(E'vah_sp_l',E'"\'@\'"',E'param',E'C',E'Vahy - seznam spartu pro vazeni ',0,7 ,E'VAHY ',E'',E'',E'vah_comm;<>;0 ',E'',E'Vahy - seznam spartu pro vazeni ',E'Vahy - seznam spartu pro vazeni ',E'',E'',E'',E'multi;spart_kas;VAH',0),
|
||||||
|
(E'vah_baud',E'9600',E'param',E'N',E'Vahy - baud rate ',0,3 ,E'VAHY ',E'',E',19200,9600,4800,2400,1200 ',E'vah_comm;<>;0 ',E'',E'Vahy - baud rate ',E'Vahy - baud rate ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_datb',E'8',E'param',E'N',E'Vahy - datove bity ',0,5 ,E'VAHY ',E'',E',5,6,7,8 ',E'vah_comm;<>;0 ',E'',E'Vahy - datove bity ',E'Vahy - datove bity ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_dotaz',E'.T.',E'param',E'L',E'Ptát se při markování váženého zboží ',0,9 ,E'VAHY ',E'',E'',E'vah_comm;<>;0 ',E'',E'Ptát se při markování váženého zboží ',E'Ptát se při markování váženého zboží ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_tara0',E'.F.',E'param',E'L',E'Automaticky nulovat táru po opuštění objednávky ',0,13,E'VAHY ',E'',E'',E'',E'',E'Automaticky nulovat táru po opuštění objednávky ',E'Automaticky nulovat táru po opuštění objednávky ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_typ',E'"CAS"',E'param',E'C',E'Typ vahy:DS650,TOLEDO,CAS ',1,2 ,E'VAHY ',E'',E',DS650,TOLEDO,CAS ',E'vah_comm;<>;0 ',E'',E'Typ vahy:DS650,TOLEDO,CAS ',E'Typ vahy:DS650,TOLEDO,CAS ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_parita',E'0',E'param',E'N',E'Vahy - parita ',0,6 ,E'VAHY ',E'',E',0,1,2 ',E'vah_comm;<>;0 ',E'',E'Vahy - parita ',E'Vahy - parita ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_delit',E'1',E'param',E'N',E'Delitel pro prepocet vahy na kq (dkg..) ',1,8 ,E'VAHY ',E'',E'',E'vah_comm;<>;0 ',E'',E'Delitel pro prepocet vahy na kq (dkg..) ',E'Delitel pro prepocet vahy na kq (dkg..) ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_comm',E'0',E'param',E'N',E'Vahy - comm ',0,1 ,E'VAHY ',E'',E'',E'',E'',E'Vahy - comm ',E'Vahy - comm ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_interv',E'200',E'param',E'N',E'Interval dotazovani na vahu [ms] ',1,10,E'VAHY ',E'',E'',E'vah_comm;<>;0 ',E'',E'Interval dotazovani na vahu [ms] ',E'Interval dotazovani na vahu [ms] ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_bezkoe',E'.F.',E'param',E'L',E'Zadavat primo jednotky misto vahy ',0,11,E'VAHY ',E'',E'',E'',E'',E'Zadavat primo jednotky misto vahy ',E'Zadavat primo jednotky misto vahy ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_online',E'.F.',E'param',E'L',E'Ukazovanie vahy online pocas vazenia ',0,12,E'VAHY ',E'',E'',E'',E'',E'Ukazovanie vahy online pocas vazenia ',E'Ukazovanie vahy online pocas vazenia ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_zmenmn',E'.F.',E'param',E'L',E'Mozne menit vahu na vazenom tovare ',0,14,E'VAHY ',E'',E'',E'',E'',E'Mozne menit vahu na vazenom tovare ',E'Mozne menit vahu na vazenom tovare ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_stopb',E'1',E'param',E'N',E'Vahy - stop bity ',0,4 ,E'VAHY ',E'',E',0,1,2 ',E'vah_comm;<>;0 ',E'',E'Vahy - stop bity ',E'Vahy - stop bity ',E'',E'',E'',E'',0),
|
||||||
|
(E'foodman_weight_items',E'0_0;1_0.15;2_0.20;3_0.35' ,E'param',E'C',E'Váhy - taniere ',0,15,E'VAHY',E'',E'',E'',E'',E'Váhy - taniere',E'Váhy - taniere',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_protocol',E'nci.pos',E'param',E'C',E'Váhy - komunikačný protokol ',0,16,E'VAHY',E'',E'nci.pos,cas,4.2.25,tscale ',E'',E'',E'Váhy - komunikačný protokol',E'Váhy - komunikačný protokol',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_scanner',E'.F.',E'param',E'L',E'Používa sa váho-skener ',0,17,E'VAHY',E'',E'',E'',E'',E'Používa sa váho-skener',E'Používa sa váho-skener',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_scanner_url',E'"127.0.0.1:5001"',E'param',E'C',E'IP:PORT na komunikáciu s váho-skenerom ',0,18,E'VAHY',E'',E'',E'weight_scanner;=;.T. ',E'',E'IP:PORT na komunikáciu s váho-skenerom ',E'IP:PORT na komunikáciu s váho-skenerom ',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_scanner_auto_confirm',E'.f.',E'param',E'L',E'Váho-skener autopotvrdzovanie ',0,19,E'VAHY',E'',E'',E'weight_scanner;=;.T. ',E'',E'Váho-skener autopotvrdzovanie',E'Váho-scaner autopotvrdzovanie',E'',E'',E'',E'',0),
|
||||||
|
(E'peripherals_socket_url',E'"127.0.0.1:5001"',E'param',E'C',E'IP:PORT na komunikáciu cez AltoPripherals',0,10 ,E'VAHY',E'',E'',E'',E'',E'',E'IP:PORT na komunikáciu cez AltoPripherals',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_dialog_allow_tare',E'.f.',E'param',E'L',E'Zobrazit tlačítko TARE v okne na váženie tovaru?',0,21 ,E'VAHY',E'',E'',E'',E'',E'Zobrazit tlačítko TARE v okne na váženie tovaru?',E'Zobrazit tlačítko TARE v okne na váženie tovaru?',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_dialog_tare_send',E'.f.',E'param',E'L',E'Posielať príkaz TARE do váhy?',0,22 ,E'VAHY',E'',E'',E'',E'',E'Posielať príkaz TARE do váhy?',E'Posielať príkaz TARE do váhy?',E'',E'',E'',E'',0),
|
||||||
|
(E'weight_dialog_allow_null',E'.f.',E'param',E'L',E'Zobrazit tlačítko RESET v okne na váženie tovaru?',0,23 ,E'VAHY',E'',E'',E'',E'',E'Zobrazit tlačítko RESET v okne na váženie tovaru?',E'Zobrazit tlačítko RESET v okne na váženie tovaru?',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_ident',E'"21"',E'param',E'C',E'Identifikace vazeneho zbozi na car. ',1,51,E'VAHY',E'',E'',E'',E'',E'Identifikace vazeneho zbozi na car. ',E'Identifikace vazeneho zbozi na car. ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_lnplu',E'5',E'param',E'N',E'Delka kodu vazeneho zbozi na car.ko ',1,52,E'VAHY',E'',E'',E'',E'',E'Delka kodu vazeneho zbozi na car.ko ',E'Delka kodu vazeneho zbozi na car.ko ',E'',E'',E'',E'',0),
|
||||||
|
(E'vah_lnvah',E'5',E'param',E'N',E'Delka kodu vahy na car.kodu ',1,53,E'VAHY',E'',E'',E'',E'',E'Delka kodu vahy na car.kodu ',E'Delka kodu vahy na car.kodu ',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
--- VERNOSTNE SYSTEMY (D-EDGE, LOYALMAN, MORETHANDINING, RON)
|
||||||
|
---
|
||||||
|
(E'loyalty_system',E'"loyalman"',E'param',E'C',E'Typ pouziteho vernostneho systemu',0,2 ,E'LOYALTY',E'',E'd-edge,loyalman,morethandining,ron',E'',E'',E'Typ pouziteho vernostneho systemu',E'Typ pouziteho vernostneho systemu',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
--- D-EDGE
|
||||||
|
(E'd_edge_user',E'"altoPOS.Webservice"',E'param',E'C',E'D-Edge username',0,2 ,E'D-EDGE',E'',E'',E'',E'',E'D-Edge username',E'D-Edge username',E'',E'',E'',E'',0),
|
||||||
|
(E'd_edge_pass',E'"46b88408-d614-4"',E'param',E'C',E'D-Edge password',0,3 ,E'D-EDGE',E'',E'',E'',E'',E'D-Edge password',E'D-Edge password',E'',E'',E'',E'',0),
|
||||||
|
(E'd_edge_enabled',E'.f.',E'param',E'L',E'Povolit D-Edge?',0,1 ,E'D-EDGE',E'',E'',E'',E'',E'Povolit D-Edge?',E'Povolit D-Edge?',E'',E'',E'',E'',0),
|
||||||
|
(E'd_edge_property_id',E'1',E'param',E'N',E'D-Edge Property ID',0,4 ,E'D-EDGE',E'',E'',E'',E'',E'D-Edge Property ID',E'D-Edge Property ID',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
-- LOYALMAN
|
||||||
|
(E'loyalman_full_users_info' ,E'.T.',E'param',E'L',E'Zobraziť info o zákaznikovi ',0,3 ,E'LoyalMan',E'',E'',E'',E'',E'Zobraziť info o zákaznikov',E'Zobraziť info o zákaznikov',E'',E'',E'',E'',0),
|
||||||
|
(E'enable_loyalman',E'.t.',E'param',E'L',E'Povolená komunikácia s LoyalManom ',0,1 ,E'LoyalMan',E'',E'',E'',E'',E'Povolená komunikácia s LoyalManom',E'Povolená komunikácia s LoyalManom',E'',E'',E'',E'',0),
|
||||||
|
(E'loyalman_discount_text_on_bill',E'""',E'param',E'C',E'Názov loyalman zľavy na účte',0,2 ,E'LoyalMan',E'',E'',E'',E'Zadefinovaný text bude vypísaný na účte. Ak je zadefinovaný text: "#discount_package#" tak vypíše názov balíka alebo od loyalman verzie 1.3.4 text na účet. Ak je prázdne vypíše default text definovaný na kase ("LoyalMan zľava na účet")',E'Názov loyalman zľavy na účte',E'Názov loyalman zľavy na účte',E'',E'',E'','', 0),
|
||||||
|
(E'loyalman_discount_fastmenu_enabled',E'.F.',E'param',E'L',E'Má sa dávať loyalman zľava na fastmenu?',0,3 ,E'LoyalMan',E'',E'',E'',E'true = aj na fast menu bude aplikovaná loyalman zľava\nfalse = na fast menu nebude aplikovaná loyalman zľava (default)',E'Má sa dávať loyalman zľava na fastmenu?',E'Má sa dávať loyalman zľava na fastmenu?',E'',E'',E'','', 0),
|
||||||
|
|
||||||
|
-- MORETHANDINING
|
||||||
|
(E'morethandining_enabled',E'.f.',E'param',E'L',E'Povolená komunikácia s MTD',0,1 ,E'MTD',E'',E'',E'',E'',E'Povolená komunikácia s MTD',E'Povolená komunikácia s MTD',E'',E'',E'',E'',0),
|
||||||
|
(E'morethandining_url',E'"http://www.morethandining.com/interface"',E'param',E'C',E'URL pre komunikaciu s MTD API',0,2 ,E'MTD',E'',E'http://www.morethandining.com/interface,http://demo.morethandining.cdi.cz/interface',E'',E'',E'URL pre komunikaciu s MTD API',E'URL pre komunikaciu s MTD API',E'',E'',E'',E'',0),
|
||||||
|
(E'morethandining_restaurant',E'""',E'param',E'C',E'Nazov prevadzky v MTD systeme',0,3 ,E'MTD',E'',E'',E'',E'',E'Nazov prevadzky v MTD systeme',E'Nazov prevadzky v MTD systeme',E'',E'',E'','', 0),
|
||||||
|
(E'morethandining_ftp_host',E'""',E'param',E'C',E'MTD FTP Server - hostname/IP',0,4 ,E'MTD',E'',E'',E'',E'',E'MTD FTP Server - hostname/IP',E'MTD FTP Server - hostname/IP',E'',E'',E'','', 0),
|
||||||
|
(E'morethandining_ftp_user',E'""',E'param',E'C',E'MTD FTP Server - username',0,5 ,E'MTD',E'',E'',E'',E'',E'MTD FTP Server - username',E'MTD FTP Server - username',E'',E'',E'','', 0),
|
||||||
|
(E'morethandining_ftp_password',E'""',E'param',E'C',E'MTD FTP Server - password',0,6 ,E'MTD',E'',E'',E'',E'',E'MTD FTP Server - password',E'MTD FTP Server - password',E'',E'',E'','', 0),
|
||||||
|
(E'morethandining_ftp_dir',E'""',E'param',E'C',E'MTD FTP Server - folder',0,7 ,E'MTD',E'',E'',E'',E'',E'MTD FTP Server - folder',E'MTD FTP Server - folder',E'',E'',E'','', 0),
|
||||||
|
(E'morethandining_druh_pl',E'""',E'param',E'C',E'Nazev z druhy_pl pouzity pre MTD zlavu',0,8 ,E'MTD',E'',E'',E'',E'musi existovat ako platobna metoda zadefinovana v druhy_pl',E'Nazev z druhy_pl pouzity pre MTD zlavu',E'Nazev z druhy_pl pouzity pre MTD zlavu',E'',E'',E'','', 0),
|
||||||
|
|
||||||
|
-- RON
|
||||||
|
(E'ron_wsdl_url',E'""',E'param',E'C',E'WSDL URL pre komunikáciu s RON ',0,2 ,E'RON',E'',E'',E'',E'',E'WSDL URL pre komunikáciu s RON',E'WSDL URL pre komunikáciu s RON',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- KVERKOM
|
||||||
|
---
|
||||||
|
(E'kverkom_ws_host',E'""',E'param',E'C',E'KVERKOM WebSocket Server - hostname/IP',0,1,E'KVERKOM',E'',E'',E'',E'',E'KVERKOM WebSocket Server - hostname/IP',E'KVERKOM WebSocket Server - hostname/IP',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_ws_port',E'8765',E'param',E'N',E'KVERKOM WebSocket Server - port',0,2,E'KVERKOM',E'',E'',E'',E'',E'KVERKOM WebSocket Server - port',E'KVERKOM WebSocket Server - port',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_erp_host',E'"api-erp.kverkom.sk"',E'param',E'C',E'KVERKOM notifikacny server',0,3,E'KVERKOM',E'',E'',E'',E'Kverkom notifikacny server\napi-erp.kverkom.sk - produkcne prostredie (default)\napi-erp-i.kverkom.sk - testovacie prostredie)',E'KVERKOM notifikacny server',E'KVERKOM notifikacny server',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_mqtt_host',E'"mqtt.kverkom.sk"',E'param',E'C',E'KVERKOM MQTT Server - hostname/IP',0,4,E'KVERKOM',E'',E'',E'',E'Kverkom MQTT server\nmqtt.kverkom.sk - produkcne prostredie (default)\nmqtt-i.kverkom.sk - testovacie prostredie)',E'KVERKOM MQTT Server - hostname/IP',E'KVERKOM MQTT Server - hostname/IP',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_ca_bundle',E'"kverkom-prod-ca-bundle"',E'param',E'C',E'KVERKOM CA certifikat',0,5,E'KVERKOM',E'',E'kverkom-prod-ca-bundle,kverkom-test-ca-bundle',E'',E'Kverkom CA certifikat:\nkverkom-prod-ca-bundle - produkcne prostredie (default)\nkverkom-test-ca-bundle - testovacie prostredie',E'KVERKOM CA certifikat',E'KVERKOM CA certifikat',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_timeout',E'120',E'param',E'N',E'Dlzka cakania na notifikaciu o kverkom platbe',0,6,E'KVERKOM',E'',E'',E'',E'Kolko sekund cakat na uspesnu notifikaciu o kverkom platbe?\ndefault 120s',E'Dlzka cakania na notifikaciu o kverkom platbe',E'Dlzka cakania na notifikaciu o kverkom platbe',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_timeout_allow_prolong',E'".f."',E'param',E'L',E'Je povolene predlzit cakanie na notifikaciu?',0,7,E'KVERKOM',E'',E'',E'',E'Je povolene predlzit cakanie na kverkom notifikaciu o platbe?\n(default false)',E'Je povolene predlzit cakanie na notifikaciu?',E'Je povolene predlzit cakanie na notifikaciu?',E'',E'',E'','', 0),
|
||||||
|
(E'kverkom_storno',E'3',E'param',E'N',E'Typ storna pre kverkom',0,8,E'KVERKOM',E'',E'0,1,2,3',E'',E'0 - peniaze sa vracajú v hotovosti\n1 - storno s tlacou ziadosti o vratenie platby\n2 - storno je zakázané\n3 - storno bez tlace ziadosti o vratenie platby',E'Typ storna pre kverkom',E'Typ storna pre kverkom',E'',E'',E'',E'',0),
|
||||||
|
(E'kverkom_storno_no_print_druhpl',E'"HOTOVE"',E'param',E'C',E'Platba pri storne kverkom uctu',0,9,E'KVERKOM',E'',E'',E'',E'',E'''druh_pl, pri storne ak kverkom_storno=3',E'',E'',E'',E'',E'uni;druhy_pl;HOTOVE',0),
|
||||||
|
(E'kverkom_qr_type',E'"payme"',E'param',E'C',E'Typ QR kodu:',0,10,E'KVERKOM',E'',E'payme',E'',E'Typ generovaneho QR kodu - dostupne moznosti:\n - payme',E'Typ QR kodu:',E'Typ QR kodu:',E'',E'',E'','', 0),
|
||||||
|
|
||||||
|
(E'qr_border',E'4',E'param',E'N',E'QR ohranicenie stvorca',0,11,E'KVERKOM',E'',E'',E'',E'QR ohranicenie stvorca (default 4)',E'',E'',E'',E'',E'','', 0),
|
||||||
|
(E'qr_box_size',E'10',E'param',E'N',E'QR velkost stvorca',0,12,E'KVERKOM',E'',E'',E'',E'QR velkost stvorca (1-16, default 10)',E'',E'',E'',E'',E'','', 0),
|
||||||
|
(E'payme_url',E'"https://payme.sk/2"',E'param',E'C',E'payme base url',0,13,E'KVERKOM',E'',E'',E'',E'payme base URL (https://payme.sk/2)',E'',E'',E'',E'',E'','', 0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- ZLAVY
|
||||||
|
---
|
||||||
|
(E'is_sleva_rychla_pl',E'.F.',E'param',E'L',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku?',0,0 ,E'ZLAVY ',E'',E'',E'',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku?',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku ',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku ',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku',E'Ma sa pokladna pytat na zlavu po rychlom tlacitku',E'',0),
|
||||||
|
(E'enable_discount_due_to_expiration_date',E'.f.',E'param',E'L',E'Povolené dať zľavu na položku pri konci záruky?',0,1 ,E'ZLAVY ',E'',E'',E'',E'',E'',E'Povolené dať zľavu na položku pri konci záruky?',E'',E'',E'',E'',0),
|
||||||
|
(E'enable_discount_due_to_expiration_date_percentage',E'0',E'param',E'N',E'Zľava pri konci záruky',0,1 ,E'ZLAVY ',E'',E'',E'',E'',E'',E'Zľava pri konci záruky',E'',E'',E'',E'',0),
|
||||||
|
(E'hh_price_level_discount',E'.f.',E'param',E'L',E'Happy Hour cenová hladina sa správa ako zľava',0,2 ,E'ZLAVY',E'',E'',E'',E'',E'Happy Hour cenová hladina sa správa ako zľava',E'Happy Hour cenová hladina sa správa ako zľava',E'',E'',E'',E'',0),
|
||||||
|
(E'hh_percentual_discount',E'.f.',E'param',E'L',E'Happy Hour percentuálna zlava sa správa ako zľava',0,3 ,E'ZLAVY',E'',E'',E'',E'',E'Happy Hour percentuálna zlava sa správa ako zľava',E'Happy Hour percentuálna zlava sa správa ako zľava',E'',E'',E'',E'',0),
|
||||||
|
(E'hh_x_k_discount',E'.f.',E'param',E'L',E'Happy Hour x+k sa správa ako zľava',0,4 ,E'ZLAVY',E'',E'',E'',E'',E'Happy Hour x+k sa správa ako zľava',E'Happy Hour x+k sa správa ako zľava',E'',E'',E'',E'',0),
|
||||||
|
(E'hk_sl_spl',E'"XXX"',E'param',E'C',E'Zoznam spartov, na ktoré sa nedáva zľava ',0,0 ,E'ZLAVY',E'',E'',E'',E'',E'Zoznam spartov, na ktoré sa nedáva zľava',E'Zoznam spartov, na ktoré sa nedáva zľava',E'',E'',E'',E'multi;spart_kas;@',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- FOODIE SYSTEMOVE
|
||||||
|
---
|
||||||
|
(E'heartbeat_show_api_unavail_after_x_missing',E'1',E'param',E'N',E'Kolko neprejdenych heartbaatov = chyba?',1,1 ,E'FOODIE SYS',E'',E'',E'',E'',E'Kolko neprejdenych heartbaatov = chyba?',E'Kolko neprejdenych heartbaatov = chyba?',E'',E'',E'',E'',0),
|
||||||
|
(E'heartbeat_interval',E'5',E'param',E'N',E'Ako casto (v sekundach) chodi heartbeat?',1,2 ,E'FOODIE SYS',E'',E'',E'',E'Definuje ako casto (v sekundach) chodi heartbeat request z foodieho na API server pre zistovanie jeho dostupnosti\ndefault hodnota = 5\n0 = nikdy neposielat heartbeat requesty',E'Ako casto (v sekundach) chodi heartbeat?',E'Ako casto (v sekundach) chodi heartbeat?',E'',E'',E'',E'',0),
|
||||||
|
(E'heartbeat_timeout',E'5',E'param',E'N',E'Kolko sekund cakat na odpoved z heartbeatu?',1,3 ,E'FOODIE SYS',E'',E'',E'',E'Po kolkych sekundach od odoslania heartbeat poziadavky vyhodnoti Foodie,\nze je API server nedostupny.\ndefault hodnota = 7',E'Kolko sekund cakat na odpoved z heartbeatu?',E'Kolko sekund cakat na odpoved z heartbeatu?',E'',E'',E'',E'',0),
|
||||||
|
(E'frontend_logging',E'.F.',E'param',E'L',E'Logovať operácie FE? (zmazanie čiernych riadkov)',0,4 ,E'FOODIE SYS',E'',E'',E'',E'Logovať operácie FE? (zmazanie čiernych riadkov)',E'Logovať operácie FE? (zmazanie čiernych riadkov)',E'Logovať operácie FE? (zmazanie čiernych riadkov)',E'',E'',E'',E'',0),
|
||||||
|
(E'frontend_logging_max_entries',E'100',E'param',E'N',E'Max.počet neodoslaných log záznamov z FE',0,5 ,E'FOODIE SYS',E'',E'',E'',E'Max.počet neodoslaných log záznamov z FE - musí byť >= 100',E'Max.počet neodoslaných log záznamov z FE',E'Max.počet neodoslaných log záznamov z FE',E'',E'',E'',E'',0),
|
||||||
|
(E'frontend_logging_sync_interval',E'15',E'param',E'N',E'Perióda odosielania logov FE na API >10',0,6 ,E'FOODIE SYS',E'',E'',E'',E'Perióda odosielania logov FE na API - musí byť >= 10',E'Perióda odosielania logov FE na API',E'Perióda odosielania logov FE na API',E'',E'',E'',E'',0),
|
||||||
|
(E'frontend_logging_heartbeat',E'.f.',E'param',E'L',E'Zapnute frontend logovanie heartbeat chyb?',1,7 ,E'FOODIE SYS',E'',E'',E'',E'Ci sa maju na frontend-e logovat (a nasledne po dostupnosti\nodosielat na API server) chyby suvisiace s heartbeat\nrequestami.\ndefault = False (nelogovat)\n\n!!! Funguje iba ak je zapnute K32.frontend_logging !!!',E'Zapnute frontend logovanie heartbeat chyb?',E'Zapnute frontend logovanie heartbeat chyb?',E'',E'',E'',E'',0),
|
||||||
|
(E'frontend_logging_local_orderline_delete',E'.f.',E'param',E'L',E'Zapnute frontend logovanie mazania poloziek?',1,8 ,E'FOODIE SYS',E'',E'',E'',E'Ci sa ma na frontend-e logovat (a nasledne odosielat na API server) mazanie lokalnych\n(nepotvrdenych) poloziek z objednavky.\ndefault = True (logovat)\n\n!!! Funguje iba ak je zapnute K32.frontend_logging !!!',E'Zapnute frontend logovanie mazania poloziek?',E'Zapnute frontend logovanie mazania poloziek?',E'',E'',E'',E'',0),
|
||||||
|
(E'virtualized_tables_grid_buffer_px',E'300',E'param',E'N',E'TEST - mobil - buffer px mapa stolov',1,0 ,E'FOODIE SYS',E'',E'',E'',E'',E'TEST - mobil - buffer px mapa stolov',E'TEST - mobil - buffer px mapa stolov',E'',E'',E'',E'',0),
|
||||||
|
(E'virtualized_orderline_sheet_buffer_px',E'300',E'param',E'N',E'TEST - mobil - buffer px objednavka',1,0 ,E'FOODIE SYS',E'',E'',E'',E'',E'TEST - mobil - buffer px objednavka',E'TEST - mobil - buffer px objednavka',E'',E'',E'',E'',0),
|
||||||
|
|
||||||
|
---
|
||||||
|
--- -----
|
||||||
|
---
|
||||||
|
(E'def_akce',E'3',E'param',E'N',E'Def. akce po přihlásení (3 objedn.)',0,50,E'----- ',E'',E'',E'',E'',E'Def. akce po přihlásení (3 objedn.)',E'Def. akce po přihlásení (3 objedn.)',E'',E'',E'',E'',0);
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
server pro pokladnu:
|
||||||
|
|
||||||
|
-přes openVPN
|
||||||
|
ip adresa: 192.168.180.133
|
||||||
|
user: altohlu\demo22
|
||||||
|
pass: Prihlaseni.0622
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
m:
|
||||||
|
cd \pokladna
|
||||||
|
|
||||||
|
call v3.12\Scripts\activate
|
||||||
|
rem uvicorn server_sqlite:app --reload --host 0.0.0.0 --port 8000
|
||||||
|
python kivy_app.py
|
||||||
|
deactivate
|
||||||
|
pause
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
m:
|
||||||
|
cd\pokladna
|
||||||
|
m:\pokladna\v3.12\Scripts\python.exe local_print_agent.py --config local_print_agent.example.json
|
||||||
|
pause
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
m:
|
||||||
|
cd\pokladna
|
||||||
|
call m:\pokladna\v3.12\scripts\activate
|
||||||
|
uvicorn server_sqlite:app --host 0.0.0.0 --port 8000 --timeout-keep-alive 120
|
||||||
|
rem deactivate
|
||||||
|
pause
|
||||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
|||||||
|
# nacti uzaverku
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
# ---------- API context ----------
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="01",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
ctx = get_ctx()
|
||||||
|
# ---------- login ----------
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
# ---------- dotaz na seznam uzávěrek ----------
|
||||||
|
closures, err = api_call.load_closures_API( ctx)
|
||||||
|
if err:
|
||||||
|
print(err)
|
||||||
|
exit()
|
||||||
|
# ---------- poslední 2 uzávěrky ----------
|
||||||
|
print("\nNAČÍTÁM POSLEDNÍ 2 UZÁVĚRKY:\n")
|
||||||
|
for c in closures[:2]:
|
||||||
|
print(
|
||||||
|
"UZÁVĚRKA:",
|
||||||
|
c.clsrep_no,
|
||||||
|
c.ucislo_od,
|
||||||
|
c.ucislo_do,
|
||||||
|
c.closed_at_od,
|
||||||
|
c.closed_at_do,
|
||||||
|
)
|
||||||
|
# ---------- načti detail uzávěrky ----------
|
||||||
|
detail, err = api_call.closure_detail_API(ctx, c.clsrep_no)
|
||||||
|
if err:
|
||||||
|
print("CHYBA:", err)
|
||||||
|
continue
|
||||||
|
print("POČET ÚČTŮ:", len(detail["ucty"]))
|
||||||
|
print("CLSREP:", detail["data"])
|
||||||
|
for u in detail["ucty"]:
|
||||||
|
print(" UCET:", u.get("ucislo"))
|
||||||
|
print()
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# nacti ucty, ktere nejsou v uzaverce
|
||||||
|
import api_call
|
||||||
|
from pydantic import SecretStr
|
||||||
|
|
||||||
|
# ---------- API context ----------
|
||||||
|
def get_ctx():
|
||||||
|
ctx = api_call.ApiContext(
|
||||||
|
user="Alto",
|
||||||
|
base_url="http://127.0.0.1:8000",
|
||||||
|
refresh_url="http://127.0.0.1:8000",
|
||||||
|
client_id="99",
|
||||||
|
id_kas="07",
|
||||||
|
username="Kobrle",
|
||||||
|
password=SecretStr("heslo"),
|
||||||
|
)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
ctx = get_ctx()
|
||||||
|
|
||||||
|
# ---------- login ----------
|
||||||
|
api_call.login_API(ctx)
|
||||||
|
|
||||||
|
# ---------- načtení účtů mimo uzávěrku ----------
|
||||||
|
ucty, err = api_call.load_ucty_notinclsrep_API(ctx)
|
||||||
|
if err:
|
||||||
|
print(err)
|
||||||
|
exit()
|
||||||
|
api_call.logout_API(ctx)
|
||||||
|
# ---------- výpis ----------
|
||||||
|
print("\nÚČTY MIMO UZÁVĚRKU:\n")
|
||||||
|
|
||||||
|
if not ucty:
|
||||||
|
print("Žádné účty k uzávěrce.")
|
||||||
|
else:
|
||||||
|
print(f"POČET ÚČTŮ: {len(ucty)}\n")
|
||||||
|
|
||||||
|
for u in ucty:
|
||||||
|
print(
|
||||||
|
"UCET:",
|
||||||
|
u.ucislo,
|
||||||
|
"| STŮL:", u.stul,
|
||||||
|
"| AUTOR:", u.autor,
|
||||||
|
"| ČAS:", u.closed_at,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------- návrh intervalu ----------
|
||||||
|
print("\nNÁVRH UZÁVĚRKY:\n")
|
||||||
|
|
||||||
|
ucislo_od = ucty[0].ucislo
|
||||||
|
ucislo_do = ucty[-1].ucislo
|
||||||
|
|
||||||
|
print("OD:", ucislo_od)
|
||||||
|
print("DO:", ucislo_do)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://192.168.0.145:8000",
|
||||||
|
"refresh_url": "http://192.168.0.145:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
+510
@@ -0,0 +1,510 @@
|
|||||||
|
# Verze upravená JQ:
|
||||||
|
# - reaguje na klávesnici
|
||||||
|
# - obsahuje ochranu proti zdvojování písmen
|
||||||
|
# - umožňuje vstup ze čtečky, případně diakritiku přemění na čísla
|
||||||
|
|
||||||
|
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.screenmanager import ScreenManager, Screen
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.uix.widget import Widget
|
||||||
|
# =====================================================
|
||||||
|
# NUMBER PAD
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
from kivy.metrics import dp
|
||||||
|
from kivy.uix.modalview import ModalView
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
# JQ
|
||||||
|
from kivy.core.window import Window
|
||||||
|
from kivy.clock import Clock
|
||||||
|
# JQ
|
||||||
|
|
||||||
|
class NumberPad(ModalView):
|
||||||
|
def _btn(self, txt):
|
||||||
|
btn = Button(text=txt)
|
||||||
|
if txt == "⌫":
|
||||||
|
btn.font_size = 36
|
||||||
|
btn.bind(on_press=lambda *_: self._press(txt))
|
||||||
|
return btn
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
mode="number",
|
||||||
|
max_len=10,
|
||||||
|
mask=False,
|
||||||
|
allow_fraction=False,
|
||||||
|
show_dot=True,
|
||||||
|
decimal_places=2,
|
||||||
|
initial_value="",
|
||||||
|
overwrite_on_first=False,
|
||||||
|
on_accept=None,
|
||||||
|
on_cancel=None,
|
||||||
|
when=None, #obsahuje time promenou pro potlaceni eventu
|
||||||
|
allow_text=False, # 🔥 NOVÉ
|
||||||
|
auto_accept_scanner=True, # 🔥 NOVÉ
|
||||||
|
scanner_timeout=0.05, # 🔥 NOVÉ
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
size_hint=(None, None),
|
||||||
|
size=(dp(360), dp(480)),
|
||||||
|
auto_dismiss=False,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.when = when
|
||||||
|
self.overwrite_on_first = overwrite_on_first
|
||||||
|
self._editing_started = False
|
||||||
|
self.on_accept = on_accept
|
||||||
|
self.on_cancel = on_cancel
|
||||||
|
self.show_dot = show_dot
|
||||||
|
# JQ
|
||||||
|
self._cz_to_num = str.maketrans("+ěščřžýáíé", "1234567890")
|
||||||
|
self.allow_text = allow_text
|
||||||
|
self.auto_accept_scanner = auto_accept_scanner
|
||||||
|
self.scanner_timeout = scanner_timeout
|
||||||
|
self._last_text = None
|
||||||
|
self._last_text_time = 0
|
||||||
|
# JQ
|
||||||
|
self._last_key_time = 0
|
||||||
|
self._scanner_buffer = ""
|
||||||
|
|
||||||
|
# --- interní stav (ZDROJ PRAVDY) ---
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self.is_fraction = False
|
||||||
|
|
||||||
|
self.mode = mode
|
||||||
|
self.allow_fraction = allow_fraction
|
||||||
|
self.decimal_places = decimal_places
|
||||||
|
self.max_len = max_len
|
||||||
|
self.mask = mask
|
||||||
|
|
||||||
|
# ---------- ROOT (JEDNOU!) ----------
|
||||||
|
root = BoxLayout(
|
||||||
|
orientation="vertical",
|
||||||
|
padding=dp(10),
|
||||||
|
spacing=dp(10),
|
||||||
|
)
|
||||||
|
self.add_widget(root)
|
||||||
|
|
||||||
|
# --- display ---
|
||||||
|
self.lbl = Label(
|
||||||
|
font_size=32,
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(60),
|
||||||
|
halign="right",
|
||||||
|
valign="middle",
|
||||||
|
)
|
||||||
|
self.lbl.bind(size=lambda *_: setattr(self.lbl, "text_size", self.lbl.size))
|
||||||
|
root.add_widget(self.lbl)
|
||||||
|
|
||||||
|
# --- keypad ---
|
||||||
|
grid = GridLayout(cols=3, spacing=dp(5), size_hint_y=1)
|
||||||
|
for txt in ["7", "8", "9", "4", "5", "6", "1", "2", "3"]:
|
||||||
|
grid.add_widget(self._btn(txt))
|
||||||
|
if self.show_dot:
|
||||||
|
grid.add_widget(self._btn("."))
|
||||||
|
else:
|
||||||
|
grid.add_widget(Label())
|
||||||
|
|
||||||
|
|
||||||
|
grid.add_widget(self._btn("0"))
|
||||||
|
grid.add_widget(self._btn("⌫"))
|
||||||
|
root.add_widget(grid)
|
||||||
|
|
||||||
|
# --- fractions ---
|
||||||
|
if self.allow_fraction:
|
||||||
|
frac = BoxLayout(size_hint_y=None, height=dp(50), spacing=dp(10))
|
||||||
|
frac.add_widget(self._btn("1/1"))
|
||||||
|
frac.add_widget(self._btn("1/2"))
|
||||||
|
frac.add_widget(self._btn("1/3"))
|
||||||
|
root.add_widget(frac)
|
||||||
|
|
||||||
|
# --- actions ---
|
||||||
|
actions = BoxLayout(size_hint_y=None, height=dp(60), spacing=dp(10))
|
||||||
|
btn_cancel = Button(text="ZRUŠIT")
|
||||||
|
btn_ok = Button(text="OK")
|
||||||
|
btn_cancel.bind(on_release=self._cancel)
|
||||||
|
btn_ok.bind(on_release=self._accept)
|
||||||
|
actions.add_widget(btn_cancel)
|
||||||
|
actions.add_widget(btn_ok)
|
||||||
|
root.add_widget(actions)
|
||||||
|
|
||||||
|
# ---------- TADY JE KLÍČ ----------
|
||||||
|
self._set_initial_value(initial_value)
|
||||||
|
self._overwrite = bool(initial_value)
|
||||||
|
self._refresh()
|
||||||
|
|
||||||
|
def _set_initial_value(self, val: str):
|
||||||
|
"""
|
||||||
|
Nastaví počáteční hodnotu NumberPadu z řetězce:
|
||||||
|
"3" nebo "3/2"
|
||||||
|
"""
|
||||||
|
if not val:
|
||||||
|
return
|
||||||
|
|
||||||
|
val = val.strip()
|
||||||
|
|
||||||
|
if "/" in val and self.allow_fraction:
|
||||||
|
try:
|
||||||
|
a, b = val.split("/", 1)
|
||||||
|
self.num = a
|
||||||
|
self.den = b
|
||||||
|
self.is_fraction = (b != "1")
|
||||||
|
except Exception:
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self.is_fraction = False
|
||||||
|
else:
|
||||||
|
# čisté číslo
|
||||||
|
self.num = val
|
||||||
|
self.den = "1"
|
||||||
|
self.is_fraction = False
|
||||||
|
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
for w in self.children[0].children:
|
||||||
|
if hasattr(w, "disabled"):
|
||||||
|
w.disabled = True
|
||||||
|
# -------------------------------------------------
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self.value = ""
|
||||||
|
self._refresh()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Resetuje NumberPad do počátečního stavu
|
||||||
|
"""
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self.is_fraction = False
|
||||||
|
self.value = ""
|
||||||
|
self._refresh()
|
||||||
|
|
||||||
|
def _press(self, txt):
|
||||||
|
print(txt)
|
||||||
|
def _start_new_input(self):
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self._editing_started = True
|
||||||
|
self.is_fraction = False
|
||||||
|
self._overwrite = False
|
||||||
|
# code: žádná fraction, žádná tečka
|
||||||
|
if self.mode == "code":
|
||||||
|
if txt in ("1/1", "1/2", "1/3"):
|
||||||
|
return
|
||||||
|
# fraction: žádná desetinná tečka
|
||||||
|
if self.allow_fraction and txt == ".":
|
||||||
|
return
|
||||||
|
# BACKSPACE
|
||||||
|
if txt == "⌫":
|
||||||
|
self._scanner_buffer = "" # 🔥 FIX
|
||||||
|
if self.num:
|
||||||
|
# mažu poslední cifru čitatele
|
||||||
|
self.num = self.num[:-1]
|
||||||
|
else:
|
||||||
|
# čitatel prázdný → ruším fraction (zpět na /1)
|
||||||
|
if self.allow_fraction and self.den != "1":
|
||||||
|
self.den = "1"
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
# FRACTION
|
||||||
|
if txt in ("1/1", "1/2", "1/3"):
|
||||||
|
if not self.allow_fraction:
|
||||||
|
return
|
||||||
|
new_den = txt.split("/")[1] # "1", "2", "3"
|
||||||
|
# toggle chování
|
||||||
|
if self.den == new_den:
|
||||||
|
self.den = "1"
|
||||||
|
else:
|
||||||
|
self.den = new_den
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
# DESETINNÁ TEČKA (jen decimal režim)
|
||||||
|
if txt == ".":
|
||||||
|
if not self.show_dot or self.allow_fraction:
|
||||||
|
return
|
||||||
|
if "." in self.num: return
|
||||||
|
if self._overwrite:
|
||||||
|
self._start_new_input()
|
||||||
|
self.num = self.num + "." if self.num else "0."
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
|
||||||
|
# ČÍSLICE
|
||||||
|
# ---- CODE REŽIM ----
|
||||||
|
if self.mode == "code":
|
||||||
|
if len(self.num) < self.max_len:
|
||||||
|
self.num += txt
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
# ---- DECIMAL REŽIM (bez fraction) ----
|
||||||
|
if not self.allow_fraction:
|
||||||
|
# simulace budoucí hodnoty
|
||||||
|
if self._overwrite:
|
||||||
|
self._start_new_input()
|
||||||
|
|
||||||
|
new_num = self.num + txt if self.num else txt # kontrola desetinných míst
|
||||||
|
if "." in new_num:
|
||||||
|
_, dec_part = new_num.split(".", 1)
|
||||||
|
if len(dec_part) > self.decimal_places:
|
||||||
|
return
|
||||||
|
# kontrola délky celé části
|
||||||
|
if "." not in self.num and len(self.num) >= self.max_len:
|
||||||
|
return
|
||||||
|
self.num = new_num
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
# ---- FRACTION REŽIM ----
|
||||||
|
if self.allow_fraction:
|
||||||
|
|
||||||
|
if self._overwrite:
|
||||||
|
# první stisk → přepíšeme čitatele, jmenovatel zachováme
|
||||||
|
self.num = txt
|
||||||
|
self._overwrite = False
|
||||||
|
else:
|
||||||
|
if len(self.num) < self.max_len:
|
||||||
|
self.num += txt
|
||||||
|
|
||||||
|
self._refresh()
|
||||||
|
return
|
||||||
|
|
||||||
|
def _start_new_input(self):
|
||||||
|
"""
|
||||||
|
Připraví NumberPad na nový vstup přepíše initial value
|
||||||
|
"""
|
||||||
|
self.num = ""
|
||||||
|
self.den = "1"
|
||||||
|
self.is_fraction = False
|
||||||
|
self._overwrite = False
|
||||||
|
|
||||||
|
|
||||||
|
def _refresh(self):
|
||||||
|
# JQ
|
||||||
|
if self.allow_text:
|
||||||
|
self.value = self.num
|
||||||
|
self.lbl.text = self.num
|
||||||
|
return
|
||||||
|
# JQ
|
||||||
|
|
||||||
|
n = self.num if self.num else "0"
|
||||||
|
# --- výstupní hodnota (datový kontrakt) ---
|
||||||
|
if self.allow_fraction:
|
||||||
|
self.value = f"{n}/{self.den}"
|
||||||
|
else:
|
||||||
|
self.value = n
|
||||||
|
# --- ZOBRAZENÍ ---
|
||||||
|
if self.mode == "code":
|
||||||
|
# 🔑 KLÍČ: při prázdném vstupu nezobrazuj NIC
|
||||||
|
if not self.num:
|
||||||
|
self.lbl.text = ""
|
||||||
|
else:
|
||||||
|
self.lbl.text = "*" * len(self.num)
|
||||||
|
return
|
||||||
|
# --- ostatní režimy ---
|
||||||
|
if not self.allow_fraction:
|
||||||
|
self.lbl.text = n
|
||||||
|
return
|
||||||
|
if self.den == "1":
|
||||||
|
self.lbl.text = n
|
||||||
|
else:
|
||||||
|
self.lbl.text = f"{n}/{self.den}"
|
||||||
|
|
||||||
|
def _compose(self) -> str:
|
||||||
|
n = self.num if self.num else "0"
|
||||||
|
if not self.allow_fraction:
|
||||||
|
# čistý numerický výstup
|
||||||
|
return n
|
||||||
|
|
||||||
|
return f"{n}/{self.den}"
|
||||||
|
|
||||||
|
def _accept(self, *_):
|
||||||
|
if not self.num:
|
||||||
|
Logger.info("IGNORE empty accept")
|
||||||
|
return
|
||||||
|
Logger.info(f"NumberPad ACCEPT: {self.value}")
|
||||||
|
self._scanner_buffer = ""
|
||||||
|
# validace fraction
|
||||||
|
if self.when:
|
||||||
|
self.when = time()
|
||||||
|
if self.allow_fraction:
|
||||||
|
try:
|
||||||
|
num, den = self.value.split("/")
|
||||||
|
if int(num) == 0:
|
||||||
|
# 0 kusů → ignorovat
|
||||||
|
self.dismiss()
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if self.on_accept:
|
||||||
|
self.on_accept(self.value)
|
||||||
|
self.dismiss()
|
||||||
|
|
||||||
|
def _cancel(self, *_):
|
||||||
|
Logger.info("NumberPad CANCEL")
|
||||||
|
if self.on_cancel:
|
||||||
|
self.on_cancel()
|
||||||
|
self.dismiss()
|
||||||
|
|
||||||
|
def enable(self):
|
||||||
|
for w in self.children[0].children:
|
||||||
|
if hasattr(w, "disabled"):
|
||||||
|
w.disabled = False
|
||||||
|
# JQ
|
||||||
|
|
||||||
|
def on_open(self):
|
||||||
|
Logger.info("NumberPad opened → bind keyboard")
|
||||||
|
Window.bind(on_key_down=self._on_key_down)
|
||||||
|
Window.bind(on_textinput=self._on_textinput)
|
||||||
|
|
||||||
|
def on_dismiss(self):
|
||||||
|
Window.unbind(on_key_down=self._on_key_down)
|
||||||
|
Window.unbind(on_textinput=self._on_textinput)
|
||||||
|
def _keyboard_closed(self):
|
||||||
|
Logger.info("Keyboard closed")
|
||||||
|
self._keyboard = None
|
||||||
|
|
||||||
|
def _on_key_down(self, *args):
|
||||||
|
# ------------------------
|
||||||
|
# NORMALIZACE ARGUMENTŮ
|
||||||
|
# ------------------------
|
||||||
|
if len(args) == 4:
|
||||||
|
# Keyboard API
|
||||||
|
keyboard, keycode, text, modifiers = args
|
||||||
|
key = keycode[1] if isinstance(keycode, tuple) else keycode
|
||||||
|
|
||||||
|
elif len(args) == 5:
|
||||||
|
# Window API
|
||||||
|
window, key, scancode, text, modifiers = args
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
now = time()
|
||||||
|
# delta = now - self._last_key_time
|
||||||
|
self._last_key_time = now
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# CONTROL KEYS
|
||||||
|
# ------------------------
|
||||||
|
# 🔥 ENTER = scanner done
|
||||||
|
# Tohle fungovalo samostatně, ale ne z volani z loginscreen
|
||||||
|
# if key in ("enter", "numpadenter", "tab", 13, 271, 9):
|
||||||
|
# if self.auto_accept_scanner and self.allow_text:
|
||||||
|
# self._accept()
|
||||||
|
# else:
|
||||||
|
# self._accept()
|
||||||
|
# return True
|
||||||
|
|
||||||
|
if key in ("enter", "numpadenter", "tab", 13, 271, 9):
|
||||||
|
if not self.num:
|
||||||
|
return True
|
||||||
|
|
||||||
|
self._accept()
|
||||||
|
return True
|
||||||
|
|
||||||
|
if key in ("escape", 27):
|
||||||
|
self._cancel()
|
||||||
|
return True
|
||||||
|
|
||||||
|
if key in ("backspace", 8):
|
||||||
|
if self.num:
|
||||||
|
self.num = self.num[:-1]
|
||||||
|
self._refresh()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _on_textinput(self, window, text):
|
||||||
|
Logger.info(f"TEXT INPUT: {text}")
|
||||||
|
|
||||||
|
# 🔥 převod CZ → čísla
|
||||||
|
if text:
|
||||||
|
text = text.translate(self._cz_to_num)
|
||||||
|
# anti-duplicate (ponecháme)
|
||||||
|
now = time()
|
||||||
|
if text == self._last_text and (now - self._last_text_time) < 0.02:
|
||||||
|
return True
|
||||||
|
|
||||||
|
self._last_text = text
|
||||||
|
self._last_text_time = now
|
||||||
|
|
||||||
|
if self.mode == "code":
|
||||||
|
for ch in text:
|
||||||
|
if ch in "0123456789*.":
|
||||||
|
self._press(ch)
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.allow_text:
|
||||||
|
allowed = set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%&?<>#*[]-_/.")
|
||||||
|
if text not in allowed:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 🔥 respektuj max_len
|
||||||
|
if self.max_len and len(self.num) >= self.max_len:
|
||||||
|
return True
|
||||||
|
|
||||||
|
self.num += text
|
||||||
|
self._refresh()
|
||||||
|
return True
|
||||||
|
|
||||||
|
for ch in text:
|
||||||
|
if ch in "0123456789":
|
||||||
|
self._press(ch)
|
||||||
|
elif ch in ",." and self.show_dot and not self.allow_fraction:
|
||||||
|
self._press(".")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
# JQ
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# TEST APP
|
||||||
|
# =====================================================
|
||||||
|
class TestApp(App):
|
||||||
|
def build(self):
|
||||||
|
return Widget() # 👈 prázdný root
|
||||||
|
|
||||||
|
def on_start(self):
|
||||||
|
def done(val):
|
||||||
|
Logger.info(f"RESULT = {val}")
|
||||||
|
|
||||||
|
# pad = NumberPad(
|
||||||
|
# mode="code",
|
||||||
|
# max_len=15,
|
||||||
|
# mask=True,
|
||||||
|
# allow_fraction=False,
|
||||||
|
# on_accept=done,
|
||||||
|
# on_cancel=lambda *_: Logger.info("CANCEL"),
|
||||||
|
# allow_text=True,
|
||||||
|
# auto_accept_scanner=True,
|
||||||
|
# )
|
||||||
|
pad = NumberPad(
|
||||||
|
mode="code",
|
||||||
|
max_len=15,
|
||||||
|
# on_accept=self._accept,
|
||||||
|
# on_cancel=self._cancel,
|
||||||
|
allow_text=True,
|
||||||
|
auto_accept_scanner=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
pad.open()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
TestApp().run()
|
||||||
+2627
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,324 @@
|
|||||||
|
#-------------------------------------------
|
||||||
|
# --- pokladna client, obchodni logika, main
|
||||||
|
#-------------------------------------------
|
||||||
|
from PySide6.QtWidgets import QApplication, QDialog, QMessageBox
|
||||||
|
import logging
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import data
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import api_call
|
||||||
|
from datetime import datetime
|
||||||
|
from api_call import ApiContext
|
||||||
|
from tisky import show_receipt_preview, Printer, ConsolePrinter
|
||||||
|
from mujUI_IV import (POSMode, POSDialog, AccountSelectDialog, StornoSelectDialog,
|
||||||
|
PosOperation, PaymentDialog, ensure_user_logged_in, STUL_RE, POS_QSS)
|
||||||
|
from mujUI_IV import (messagebox, NumberPadDialog)
|
||||||
|
#from UI_Kivy.kivy_ui import NumberPadDialog, messagebox
|
||||||
|
|
||||||
|
|
||||||
|
#from config import (user, base_url, r_url, client_id, id_kas, username,
|
||||||
|
# password, token, refresh_token)
|
||||||
|
#----------------------------------------
|
||||||
|
|
||||||
|
logger = logging.getLogger("POS")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
if not logger.handlers:
|
||||||
|
handler = logging.StreamHandler(sys.stderr) # ⬅️ DŮLEŽITÉ
|
||||||
|
formatter = logging.Formatter( "%(asctime)s [%(levelname)s] %(name)s: %(message)s" )
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
def setup_logging(debug: bool = False):
|
||||||
|
level = logging.DEBUG if debug else logging.INFO
|
||||||
|
root = logging.getLogger()
|
||||||
|
root.setLevel(level)
|
||||||
|
handler = logging.StreamHandler(sys.stderr) # ⬅️ DŮLEŽITÉ
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
"%(asctime)s [%(levelname)s] %(name)s: %(message)s" )
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
root.handlers.clear()
|
||||||
|
root.addHandler(handler)
|
||||||
|
|
||||||
|
def PosDialog_Normal(setup, cenik, ucet):
|
||||||
|
dlg = POSDialog(cenik, ucet, setup, mode=POSMode.NORMAL)
|
||||||
|
return dlg
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
debug = True #jiz jen pro tvorbu testovacich dat
|
||||||
|
setup_logging(debug = True)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
if debug:
|
||||||
|
import tst_data
|
||||||
|
user = "Petr Kobrle"
|
||||||
|
# --- client setup
|
||||||
|
apictx = ApiContext(user = "Petr Kobrle, cisnik",
|
||||||
|
base_url = "http://127.0.0.1:8000",
|
||||||
|
refresh_url = "http://127.0.0.1:8000",
|
||||||
|
client_id = "01", #terminal
|
||||||
|
id_kas = "01", #cislo pokladny
|
||||||
|
#zde udaje pro zakazku
|
||||||
|
username = "Kobrle",
|
||||||
|
password = "heslo")
|
||||||
|
|
||||||
|
# --- startuj heartbeat
|
||||||
|
api_call.start_heartbeat(ctx=apictx)
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
app.setStyle("Fusion") # důležité
|
||||||
|
app.setStyleSheet(POS_QSS)
|
||||||
|
info = {"exists": False, "blocked": False, "blocked_by": ""}
|
||||||
|
messagebox(
|
||||||
|
f"Startuje pokladna, user:{apictx.user}\nuser zakazky:{apictx.username}",)
|
||||||
|
#buttons=("OK",),) parent=None, initial_index=0)
|
||||||
|
try:
|
||||||
|
api_call.login_API(apictx)
|
||||||
|
setup = api_call.load_setup_API(apictx)
|
||||||
|
except Exception as e:
|
||||||
|
messagebox(f"Chyba startu:\n{e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
#open_printer_from_setup(setup)
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
# --- Vytvoreni a nacteni testovaciho ceniku, jen pri debug == True
|
||||||
|
api_call.debugrepl_cenik_API(apictx)
|
||||||
|
# --- Nacteni ceniku ze serveru pro danou pokladnu
|
||||||
|
cenik = api_call.load_cenik_API(apictx)
|
||||||
|
cisnik = None
|
||||||
|
max_pokusu = 3
|
||||||
|
while True:
|
||||||
|
if cisnik == None:
|
||||||
|
for pokus in range(max_pokusu):
|
||||||
|
cisnik = ensure_user_logged_in(None, apictx)
|
||||||
|
if cisnik == None:
|
||||||
|
messagebox("Zruseno prihlasovani\nPokladna se ukončí.")
|
||||||
|
sys.exit(0)
|
||||||
|
if cisnik:
|
||||||
|
apictx.user = cisnik.name
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
zbyva = max_pokusu - pokus - 1
|
||||||
|
if zbyva > 0:
|
||||||
|
messagebox(f"Neplatné přihlášení.\nZbývá {zbyva} pokusů.")
|
||||||
|
else:
|
||||||
|
#po x neúspěšných pokusech
|
||||||
|
messagebox("Překročen maximální počet pokusů.\nPokladna se ukončí.")
|
||||||
|
sys.exit(0)
|
||||||
|
# --- nacte stoly/ucty ze serveru, jen pro moji pokladnu a closed == False
|
||||||
|
ucty_row = api_call.load_stoly_API(apictx, closed = False) #vrati svoje otevrene
|
||||||
|
dlg = AccountSelectDialog(ucty_row, apictx.client_id)
|
||||||
|
if dlg.exec() != QDialog.Accepted:
|
||||||
|
break
|
||||||
|
accountselectionaction = dlg.action
|
||||||
|
|
||||||
|
if accountselectionaction == "logof":
|
||||||
|
#po logof neni vybran zadny ucet, kod musi byt zde
|
||||||
|
cisnik = None
|
||||||
|
continue
|
||||||
|
elif accountselectionaction == "uzav": #uzaverka
|
||||||
|
...
|
||||||
|
continue
|
||||||
|
elif accountselectionaction == "view":
|
||||||
|
# výběr z uzavřených účtů
|
||||||
|
ucty_closed = api_call.load_stoly_API(apictx, closed=True)
|
||||||
|
print(ucty_closed)
|
||||||
|
if not ucty_closed:
|
||||||
|
messagebox("Žádné uzavřené účty k prohlížení.")
|
||||||
|
continue
|
||||||
|
dlg = StornoSelectDialog(ucty=ucty_closed, parent=None, mode="View")
|
||||||
|
if dlg.exec() != QDialog.Accepted:
|
||||||
|
continue
|
||||||
|
ucet_sel = dlg.selected_ucet
|
||||||
|
ucet = api_call.load_ucet_by_ucislo_API(apictx, ucislo=ucet_sel.ucislo)
|
||||||
|
# 🔍 pouze náhled – žádné změny
|
||||||
|
show_receipt_preview(None, ucet)
|
||||||
|
continue
|
||||||
|
elif accountselectionaction == "stornopol":
|
||||||
|
#storno polozek z uzavrenych uctu (zatim neni Accountselection na tohle cesta)
|
||||||
|
...
|
||||||
|
continue
|
||||||
|
elif accountselectionaction == "stornuct" or accountselectionaction == "zmdrplt":
|
||||||
|
#storna z uzavrenych uctu
|
||||||
|
ucty = api_call.load_stoly_API(apictx, closed=True) #limitem a sortem na serveru
|
||||||
|
ucty_closed = [ u for u in ucty if not ((u.origin == "Storno") or (u.origin == "Stornovan") or (u.origin == "StorPaymChg"))]
|
||||||
|
storno_dlg = StornoSelectDialog( ucty=ucty_closed, parent=None,)
|
||||||
|
if storno_dlg.exec() != QDialog.Accepted: #vybrany ucet
|
||||||
|
continue
|
||||||
|
ucet = storno_dlg.selected_ucet
|
||||||
|
ucet = api_call.load_ucet_by_ucislo_API(apictx, ucislo=ucet.ucislo)
|
||||||
|
#storno, zmena druhu platby
|
||||||
|
ucet_puvodni = ucet.model_copy(deep=True) #ucet je pro storno
|
||||||
|
if not accountselectionaction == "zmdrplt":
|
||||||
|
logger.info(f"storno uctu {ucet.ucislo}" )
|
||||||
|
else:
|
||||||
|
logger.info(f"zmena druhu platby {ucet.ucislo}" )
|
||||||
|
#musime nejdriv vybrat nove platby, aby sla operace zrusit
|
||||||
|
ucet_novy = ucet.model_copy(deep=True) # novymi platbami
|
||||||
|
ucet_novy.platby = []
|
||||||
|
ucet_novy.storno = ""
|
||||||
|
ucet_novy.is_storno = f"Z{ucet_novy.ucislo}" #cislo zmeneneho
|
||||||
|
ucet_novy.ucislo = "" #bude to novy ucet
|
||||||
|
discount = ucet_novy.discount_abs
|
||||||
|
total_czk = ucet_novy.total_czk()
|
||||||
|
dlg = PaymentDialog(total=total_czk, discount_abs=discount,
|
||||||
|
parent=None, setup=setup )
|
||||||
|
if dlg.exec() != QDialog.Accepted:
|
||||||
|
#zatim jedina moznost jak odblokovat uzavreny ucet
|
||||||
|
api_call.save_ucet_API(apictx, ucet)
|
||||||
|
logger.info(f"zmena druhu platby {ucet.ucislol} zrusena" )
|
||||||
|
continue # obsluha zrušila platbu, tim i celou operaci
|
||||||
|
pay_result = dlg.result()
|
||||||
|
# vytvoř účet s novymi platbami
|
||||||
|
for p in pay_result.payments:
|
||||||
|
ucet_novy.platby.append(
|
||||||
|
data.Platba( code=p.code, nazev=p.nazev, suma=p.suma, unit=p.unit,
|
||||||
|
rate=p.rate, suma_czk=p.suma_czk, fiscal=p.fiscal, ))
|
||||||
|
ucet_novy.sumdph()
|
||||||
|
ucet_novy.stul = ""
|
||||||
|
ucet_novy.origin = "Zmena_Platby"
|
||||||
|
api_call.save_ucet_API(apictx, ucet_novy)
|
||||||
|
show_receipt_preview(None, ucet_novy)
|
||||||
|
#ted storno uctu (musi se stornovat i pro zmenu druhu platby)
|
||||||
|
ucet.autor = apictx.user
|
||||||
|
ucet.is_storno = ucet_puvodni.ucislo
|
||||||
|
ucet.origin = "Storno"
|
||||||
|
ucet.ucislo = ""
|
||||||
|
ucet.stul = ""
|
||||||
|
ucet.blocked_by = ""
|
||||||
|
ucet.closed_at = data.now_clk_str()
|
||||||
|
for dd in ucet.dane:
|
||||||
|
dd.zaklad = -dd.zaklad
|
||||||
|
ucet.datetime = data.stime_str()
|
||||||
|
ucet.discount_abs = -ucet.discount_abs
|
||||||
|
for pp in ucet.platby:
|
||||||
|
pp.suma = -pp.suma
|
||||||
|
pp.suma_czk = -pp.suma_czk
|
||||||
|
for po in ucet.poloz:
|
||||||
|
po.pocet = -po.pocet
|
||||||
|
po.kstornu = 0
|
||||||
|
resp = api_call.save_ucet_API(apictx, ucet)
|
||||||
|
show_receipt_preview(None, ucet)
|
||||||
|
ucet_puvodni.storno = resp.ucislo
|
||||||
|
ucet_puvodni.blocked_by = ""
|
||||||
|
if ucet_puvodni.origin == "Zmena_Platby":
|
||||||
|
ucet_puvodni.origin = "StorPaymChg"
|
||||||
|
#print(ucet_puvodni)
|
||||||
|
resp = api_call.save_ucet_API(apictx, ucet_puvodni)
|
||||||
|
if not resp or not resp.ucislo:
|
||||||
|
messagebox("Chyba storna operace nedokončena")
|
||||||
|
continue
|
||||||
|
#zbytek operaci pracuje s otevrenym uctem dle cisla stolu
|
||||||
|
ucet = dlg.selected_ucet
|
||||||
|
ucet = api_call.load_ucet_API(apictx, ucet.stul)
|
||||||
|
logger.debug(f"akce po vyberu stolu: {accountselectionaction},\nvybrany stul: {ucet.stul}" )
|
||||||
|
dlg = PosDialog_Normal(setup, cenik, ucet)
|
||||||
|
#print(f"u_main\n{u_main}\nu_sec\n{u_sec}\n dlg")
|
||||||
|
ret = dlg.exec()
|
||||||
|
# --- vyhodnoceni operace PosDialog
|
||||||
|
if ret != QDialog.Accepted or dlg.result is None:
|
||||||
|
api_call.unblock_ucet_API(apictx, ucet.stul)
|
||||||
|
logger.debug("POS zrušen (bez operace)")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
res = dlg.result
|
||||||
|
logger.debug( f"""Operace {res.operation}\nUcet main\n{res.ucet_main}\n
|
||||||
|
Ucet secondary\n{res.ucet_secondary}""")
|
||||||
|
u_main = res.ucet_main # doplnime chybejici udaje
|
||||||
|
u_sec = res.ucet_secondary
|
||||||
|
logger.info(f"Operace PosDialog {res.operation}")
|
||||||
|
|
||||||
|
# --- zde provedeni operaci z PosDialog
|
||||||
|
#CANCEL = "none" # opusti POSDialog bez akce, ok
|
||||||
|
#PAY_FULL = "pay_full" # platba celého účtu , ok
|
||||||
|
#PAY_PARTIAL = "pay_partial" # částečná platba
|
||||||
|
#SPLIT = "split" # rozdělení účtu
|
||||||
|
#STORNO = "storno" # storno položek
|
||||||
|
#SAVE_UCET = "save_full" # ulozi zmeny uctu , ok
|
||||||
|
|
||||||
|
if res.operation == PosOperation.SAVE_UCET:
|
||||||
|
api_call.save_ucet_API(apictx, u_main) #implicitne unblock
|
||||||
|
#tisk bonu
|
||||||
|
continue
|
||||||
|
elif res.operation == PosOperation.PAY_FULL:
|
||||||
|
u_main.autor = apictx.user
|
||||||
|
u_main.closed_at = data.now_clk_str()
|
||||||
|
u_main.datetime = data.stime_str()
|
||||||
|
u_main.sumdph()
|
||||||
|
u_main.origin = "Normal"
|
||||||
|
api_call.save_ucet_API(apictx, u_main) #implicitne unblock
|
||||||
|
#tisk uctu
|
||||||
|
#printer = ConsolePrinter(None)
|
||||||
|
#tisk_uctu(u_main, printer)
|
||||||
|
show_receipt_preview(None, u_main)
|
||||||
|
continue
|
||||||
|
elif res.operation == PosOperation.PAY_PARTIAL:
|
||||||
|
#PosDialog nepropusti castecnou platbu bez vybranych polozek
|
||||||
|
u_sec.autor = apictx.user
|
||||||
|
u_sec.closed_at = data.now_clk_str()
|
||||||
|
u_sec.datetime = data.stime_str()
|
||||||
|
u_sec.sumdph()
|
||||||
|
u_sec.origin = "Normal"
|
||||||
|
resp=api_call.save_ucet_API(apictx, u_sec) #implicitne unblock
|
||||||
|
if u_main.poloz != []:
|
||||||
|
api_call.save_ucet_API(apictx, u_main)
|
||||||
|
#ulozi se na stejne misto, ci-li UPSERT nestaras se o stary
|
||||||
|
#print(f"u_main\n{u_main}\nu_sec\n{u_sec}\n")
|
||||||
|
#printer = ConsolePrinter(None)
|
||||||
|
#tisk_uctu(u_sec, printer)
|
||||||
|
show_receipt_preview(None, u_sec)
|
||||||
|
continue
|
||||||
|
elif res.operation == PosOperation.SPLIT:
|
||||||
|
stul = ""
|
||||||
|
if u_sec.poloz!=[]: # nic nevybrano k prevodu
|
||||||
|
while True:
|
||||||
|
dlg = NumberPadDialog(None, "Zadej číslo stolu")
|
||||||
|
if dlg.exec() != QDialog.Accepted:
|
||||||
|
break
|
||||||
|
stul = str(dlg.value()).strip()
|
||||||
|
if not stul:
|
||||||
|
messagebox(
|
||||||
|
"Neplatné číslo.\nČíslo stolu nesmí být prázdné.")
|
||||||
|
continue
|
||||||
|
if not STUL_RE.match(stul):
|
||||||
|
messagebox(
|
||||||
|
"Neplatný formát.\nČíslo stolu musí mít tvar 1–999 nebo 1–999.9", )
|
||||||
|
continue
|
||||||
|
info = api_call.is_ucet_blocked_API(apictx, stul)
|
||||||
|
if info["exists"] and info["blocked"]:
|
||||||
|
block_id_kas,_ = info["blocked_by"].split("|",1) #'01|13:11:49'
|
||||||
|
if block_id_kas != apictx.id_kas:
|
||||||
|
messagebox(
|
||||||
|
f"""Účet blokován.\nStůl {stul}
|
||||||
|
je právě otevřen na jiném POS\n({info['blocked_by']})""" )
|
||||||
|
continue #nove zadani stolu
|
||||||
|
break
|
||||||
|
#print(f"u_main\n{u_main}\nu_sec\n{u_sec}\nstul {stul}\nblocked{info}")
|
||||||
|
if u_main.stul != stul and stul != "":
|
||||||
|
if u_main.poloz==[]: #prevede se vse
|
||||||
|
api_call.merge_ucet_API(apictx, u_sec, stul)
|
||||||
|
api_call.unblock_ucet_API(apictx, stul)
|
||||||
|
# pokud tam nic nezbyde
|
||||||
|
api_call.delete_ucet_API(apictx, stul=u_main.stul)
|
||||||
|
else:
|
||||||
|
api_call.save_ucet_API(apictx, u_main)
|
||||||
|
api_call.merge_ucet_API(apictx, u_sec, stul)
|
||||||
|
api_call.unblock_ucet_API(apictx, u_main.stul)
|
||||||
|
api_call.unblock_ucet_API(apictx, stul)
|
||||||
|
else:
|
||||||
|
api_call.unblock_ucet_API(apictx, u_main.stul)
|
||||||
|
else: #nic se neprevadelo, jen odblokuj u_main
|
||||||
|
api_call.unblock_ucet_API(apictx, u_main.stul)
|
||||||
|
continue
|
||||||
|
elif res.operation == PosOperation.STORNO:
|
||||||
|
#print(f"u_main\n{u_main}\nu_sec\n{u_sec}\n res.operation")
|
||||||
|
#sys.exit(0)
|
||||||
|
for i in u_sec.poloz:
|
||||||
|
#print bon z i
|
||||||
|
...
|
||||||
|
api_call.save_ucet_API(apictx, u_main)
|
||||||
|
continue
|
||||||
|
|
||||||
+7313
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
import data
|
||||||
|
|
||||||
|
|
||||||
|
class PostgresServiceError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _load_driver():
|
||||||
|
try:
|
||||||
|
import psycopg
|
||||||
|
return "psycopg", psycopg
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
import psycopg2
|
||||||
|
return "psycopg2", psycopg2
|
||||||
|
except Exception as e:
|
||||||
|
raise PostgresServiceError("Nie je nainstalovany PostgreSQL driver psycopg ani psycopg2.") from e
|
||||||
|
|
||||||
|
|
||||||
|
def is_configured(conn: data.PostgresConnection) -> bool:
|
||||||
|
return bool(
|
||||||
|
conn.host.strip()
|
||||||
|
and conn.database.strip()
|
||||||
|
and conn.user.strip()
|
||||||
|
and int(conn.port or 0) > 0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def connection_kwargs(conn: data.PostgresConnection) -> dict:
|
||||||
|
kwargs = {
|
||||||
|
"host": conn.host,
|
||||||
|
"port": int(conn.port or 5432),
|
||||||
|
"dbname": conn.database,
|
||||||
|
"user": conn.user,
|
||||||
|
"password": conn.password,
|
||||||
|
"connect_timeout": int(conn.connect_timeout or 5),
|
||||||
|
}
|
||||||
|
if conn.sslmode:
|
||||||
|
kwargs["sslmode"] = conn.sslmode
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def test_connection(conn: data.PostgresConnection) -> None:
|
||||||
|
if not conn.enabled:
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je povolene pre instalaciu.")
|
||||||
|
if not is_configured(conn):
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je vyplnene.")
|
||||||
|
driver_name, driver = _load_driver()
|
||||||
|
try:
|
||||||
|
pg = driver.connect(**connection_kwargs(conn))
|
||||||
|
try:
|
||||||
|
cur = pg.cursor()
|
||||||
|
try:
|
||||||
|
cur.execute("SELECT 1")
|
||||||
|
cur.fetchone()
|
||||||
|
finally:
|
||||||
|
cur.close()
|
||||||
|
finally:
|
||||||
|
pg.close()
|
||||||
|
except Exception as e:
|
||||||
|
raise PostgresServiceError(f"PostgreSQL spojenie zlyhalo ({driver_name}): {e}") from e
|
||||||
|
|
||||||
|
|
||||||
|
def open_connection(conn: data.PostgresConnection):
|
||||||
|
if not conn.enabled:
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je povolene pre instalaciu.")
|
||||||
|
if not is_configured(conn):
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je vyplnene.")
|
||||||
|
driver_name, driver = _load_driver()
|
||||||
|
try:
|
||||||
|
return driver.connect(**connection_kwargs(conn))
|
||||||
|
except Exception as e:
|
||||||
|
raise PostgresServiceError(f"PostgreSQL spojenie zlyhalo ({driver_name}): {e}") from e
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def connect(conn: data.PostgresConnection):
|
||||||
|
if not conn.enabled:
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je povolene pre instalaciu.")
|
||||||
|
if not is_configured(conn):
|
||||||
|
raise PostgresServiceError("PostgreSQL pripojenie nie je vyplnene.")
|
||||||
|
driver_name, driver = _load_driver()
|
||||||
|
try:
|
||||||
|
pg = driver.connect(**connection_kwargs(conn))
|
||||||
|
except Exception as e:
|
||||||
|
raise PostgresServiceError(f"PostgreSQL spojenie zlyhalo ({driver_name}): {e}") from e
|
||||||
|
try:
|
||||||
|
yield pg
|
||||||
|
finally:
|
||||||
|
pg.close()
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.label import Label
|
||||||
|
from kivy.metrics import dp
|
||||||
|
|
||||||
|
# 👉 import tvého numpadu (uprav cestu podle projektu)
|
||||||
|
from numberpad import NumberPad
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# IP + PORT INPUT (COMPACT)
|
||||||
|
# =====================================================
|
||||||
|
class IpPortInput(BoxLayout):
|
||||||
|
"""
|
||||||
|
mode:
|
||||||
|
"ip" → jen IP
|
||||||
|
"port" → jen port
|
||||||
|
"both" → IP + port
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *, mode="both", ip="192.168.0.1", port=8000, on_done=None, **kwargs):
|
||||||
|
super().__init__(
|
||||||
|
orientation="vertical",
|
||||||
|
spacing=dp(5),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(120),
|
||||||
|
padding=dp(5),
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mode = mode
|
||||||
|
self.on_done = on_done
|
||||||
|
|
||||||
|
self.ip_parts = self._parse_ip(ip)
|
||||||
|
self.port = str(port)
|
||||||
|
|
||||||
|
# ================= DISPLAY =================
|
||||||
|
self.lbl = Label(
|
||||||
|
text=self._format(),
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(25),
|
||||||
|
halign="center",
|
||||||
|
valign="middle",
|
||||||
|
)
|
||||||
|
self.lbl.bind(size=lambda *_: setattr(self.lbl, "text_size", self.lbl.size))
|
||||||
|
self.add_widget(self.lbl)
|
||||||
|
|
||||||
|
# ================= BUTTON ROW =================
|
||||||
|
row = BoxLayout(spacing=dp(3), height=dp(45), size_hint_y=None)
|
||||||
|
|
||||||
|
self.btn_ip = []
|
||||||
|
if mode in ("ip", "both"):
|
||||||
|
for i in range(4):
|
||||||
|
b = Button(text=self.ip_parts[i], font_size=14)
|
||||||
|
b.bind(on_press=lambda inst, idx=i: self._edit_ip(idx))
|
||||||
|
self.btn_ip.append(b)
|
||||||
|
row.add_widget(b)
|
||||||
|
|
||||||
|
if mode in ("port", "both"):
|
||||||
|
self.btn_port = Button(text=self.port, font_size=14)
|
||||||
|
self.btn_port.bind(on_press=self._edit_port)
|
||||||
|
row.add_widget(self.btn_port)
|
||||||
|
|
||||||
|
self.add_widget(row)
|
||||||
|
|
||||||
|
# ================= OK BUTTON =================
|
||||||
|
btn_ok = Button(
|
||||||
|
text="OK",
|
||||||
|
size_hint_y=None,
|
||||||
|
height=dp(40),
|
||||||
|
background_color=(0.2, 0.6, 0.2, 1),
|
||||||
|
)
|
||||||
|
btn_ok.bind(on_press=self._done)
|
||||||
|
self.add_widget(btn_ok)
|
||||||
|
|
||||||
|
# =================================================
|
||||||
|
# PARSE / FORMAT
|
||||||
|
# =================================================
|
||||||
|
def _parse_ip(self, ip):
|
||||||
|
try:
|
||||||
|
parts = ip.split(".")
|
||||||
|
return [str(int(p)) for p in parts[:4]]
|
||||||
|
except Exception:
|
||||||
|
return ["192", "168", "0", "1"]
|
||||||
|
|
||||||
|
def _format(self):
|
||||||
|
if self.mode == "ip":
|
||||||
|
return ".".join(self.ip_parts)
|
||||||
|
if self.mode == "port":
|
||||||
|
return self.port
|
||||||
|
return f"{'.'.join(self.ip_parts)}:{self.port}"
|
||||||
|
|
||||||
|
def get_value(self):
|
||||||
|
if self.mode == "ip":
|
||||||
|
return ".".join(self.ip_parts)
|
||||||
|
if self.mode == "port":
|
||||||
|
return int(self.port)
|
||||||
|
return ".".join(self.ip_parts), int(self.port)
|
||||||
|
|
||||||
|
# =================================================
|
||||||
|
# EDIT IP PART
|
||||||
|
# =================================================
|
||||||
|
def _edit_ip(self, idx):
|
||||||
|
def done(val):
|
||||||
|
try:
|
||||||
|
v = int(val)
|
||||||
|
if 0 <= v <= 255:
|
||||||
|
self.ip_parts[idx] = str(v)
|
||||||
|
self.btn_ip[idx].text = str(v)
|
||||||
|
self._refresh()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
NumberPad(
|
||||||
|
mode="number",
|
||||||
|
max_len=3,
|
||||||
|
allow_fraction=False,
|
||||||
|
initial_value=self.ip_parts[idx],
|
||||||
|
on_accept=done,
|
||||||
|
).open()
|
||||||
|
|
||||||
|
# =================================================
|
||||||
|
# EDIT PORT
|
||||||
|
# =================================================
|
||||||
|
def _edit_port(self, *_):
|
||||||
|
def done(val):
|
||||||
|
try:
|
||||||
|
v = int(val)
|
||||||
|
if 0 <= v <= 65535:
|
||||||
|
self.port = str(v)
|
||||||
|
self.btn_port.text = str(v)
|
||||||
|
self._refresh()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
NumberPad(
|
||||||
|
mode="number",
|
||||||
|
max_len=5,
|
||||||
|
allow_fraction=False,
|
||||||
|
initial_value=self.port,
|
||||||
|
on_accept=done,
|
||||||
|
).open()
|
||||||
|
|
||||||
|
# =================================================
|
||||||
|
# REFRESH
|
||||||
|
# =================================================
|
||||||
|
def _refresh(self):
|
||||||
|
self.lbl.text = self._format()
|
||||||
|
|
||||||
|
# =================================================
|
||||||
|
# DONE
|
||||||
|
# =================================================
|
||||||
|
def _done(self, *_):
|
||||||
|
if self.on_done:
|
||||||
|
self.on_done(self.get_value())
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# TEST APP
|
||||||
|
# =====================================================
|
||||||
|
class TestApp(App):
|
||||||
|
def build(self):
|
||||||
|
root = BoxLayout(padding=dp(20))
|
||||||
|
|
||||||
|
widget = IpPortInput(
|
||||||
|
mode="both",
|
||||||
|
ip="10.0.0.5",
|
||||||
|
port=8080,
|
||||||
|
on_done=lambda v: print("RESULT:", v),
|
||||||
|
)
|
||||||
|
|
||||||
|
root.add_widget(widget)
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
TestApp().run()
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
kivy
|
||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
pydantic
|
||||||
|
requests
|
||||||
|
qrcode[pil]
|
||||||
|
psycopg[binary]
|
||||||
|
jinja2
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"user": "SYSTEM",
|
||||||
|
"base_url": "http://192.168.180.133:8000",
|
||||||
|
"refresh_url": "http://192.168.180.133:8000/refresh/",
|
||||||
|
"client_id": "01",
|
||||||
|
"id_kas": "01",
|
||||||
|
"username": "Kobrle",
|
||||||
|
"password": "heslo",
|
||||||
|
"bill_printer": "192.168.0.148:9100",
|
||||||
|
"bon_printer1": "192.168.0.148:9100",
|
||||||
|
"bon_printer2": ""
|
||||||
|
}
|
||||||
+1015
File diff suppressed because it is too large
Load Diff
+62832
File diff suppressed because it is too large
Load Diff
+12492
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user