simikkk commited on
Commit
911ec49
·
verified ·
1 Parent(s): 81f31cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +298 -268
app.py CHANGED
@@ -5,339 +5,369 @@ import time
5
  import random
6
  import traceback
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  # -----------------------------------------------------------------------------
9
  # KONFIGURACE A INICIALIZACE STAVU
10
  # -----------------------------------------------------------------------------
11
- VERSION = "1.0.0-PRODUKČNÍ"
12
 
13
- st.set_page_config(
14
- page_title="TradeFlow AI — Systém pro řemeslníky",
15
- page_icon="🏆",
16
- layout="wide",
17
- initial_sidebar_state="expanded"
18
- )
 
 
 
 
 
19
 
20
- # Bezpečné založení session state parametrů pro uchování dat při klikání v UI
21
- if "dev_mode" not in st.session_state:
22
- st.session_state.dev_mode = True
23
- if "user_subscribed" not in st.session_state:
24
- st.session_state.user_subscribed = False
25
- if "quotes_count" not in st.session_state:
26
- st.session_state.quotes_count = 1
27
- if "stripe_mode" not in st.session_state:
28
- st.session_state.stripe_mode = "Sandbox (Simulace)"
29
- if "stripe_api_key" not in st.session_state:
30
- st.session_state.stripe_api_key = ""
31
- if "error_logs" not in st.session_state:
32
- st.session_state.error_logs = []
33
-
34
  if "db_customers" not in st.session_state:
35
  st.session_state.db_customers = [
36
  {"id": 1, "jmeno": "Jan Novák", "firma": "Stavebniny s.r.o.", "telefon": "+420 777 123 456"},
37
  {"id": 2, "jmeno": "Marie Podlahová", "firma": "Bytové družstvo", "telefon": "+420 602 987 654"}
38
  ]
39
- if "db_quotes" not in st.session_state:
40
- st.session_state.db_quotes = []
41
- if "db_invoices" not in st.session_state:
42
- st.session_state.db_invoices = []
 
 
 
 
 
 
43
 
44
  def log_system_error(err_msg, trace_str):
45
- st.session_state.error_logs.append({
46
- "time": time.strftime("%H:%M:%S"),
47
- "msg": err_msg,
48
- "trace": trace_str
49
- })
50
 
51
  # -----------------------------------------------------------------------------
52
- # BACKEND: STRIPE PLATEBNÍ PROCESOR
53
  # -----------------------------------------------------------------------------
54
  def execute_stripe_checkout(card_number, exp_month, exp_year, cvc, amount=29.00):
55
  try:
56
  if st.session_state.stripe_mode == "Stripe Live API":
57
- if not st.session_state.stripe_api_key:
58
- raise ValueError("Chybí Stripe Secret API klíč pro Live režim.")
59
  stripe.api_key = st.session_state.stripe_api_key
60
-
61
- token = stripe.Token.create(
62
- card={"number": card_number, "exp_month": int(exp_month), "exp_year": int(exp_year), "cvc": cvc}
63
- )
64
- charge = stripe.Charge.create(
65
- amount=int(amount * 100), currency="eur", source=token.id, description="TradeFlow AI Pro Tarif"
66
- )
67
  if charge.status == "succeeded":
68
  st.session_state.user_subscribed = True
69
- return True, "Platba úspěšně zpracována přes Stripe Live API!"
70
- return False, f"Stripe zamítl platbu: {charge.status}"
71
  else:
72
- # Sandbox testovací režim
73
  time.sleep(1.0)
74
- if not card_number or len(card_number.replace(" ", "")) < 16:
75
- return False, "Chyba karty: Neplatná délka čísla karty."
76
- if cvc == "000":
77
- return False, "Karta zamítnuta (Sandbox: Kód 51 - Nedostatečný zůstatek)."
78
  st.session_state.user_subscribed = True
79
- return True, "Sandbox úspěch: Licence aktivována!"
80
  except Exception as e:
81
- err_msg = f"Selhání Stripe subsystému: {str(e)}"
82
- log_system_error(err_msg, traceback.format_exc())
83
- return False, err_msg
84
 
85
- # -----------------------------------------------------------------------------
86
- # BACKEND: AI CORE & LOGIKA GENERÁTORU
87
- # -----------------------------------------------------------------------------
88
- def mock_ai_generate_quote(customer_name, text_zadani, hodinova_sazba):
89
  try:
90
  if st.session_state.quotes_count >= 3 and not st.session_state.user_subscribed:
91
- raise PermissionError("Překročen limit Free tieru (max 3 nabídky).")
92
-
93
  time.sleep(1.2)
 
94
 
95
- # Algoritmus pro analýzu klíčových slov v zadání
96
- odhad_hodin = 8
97
- if "koupeln" in text_zadani.lower() or "rekonstrukce" in text_zadani.lower():
98
- odhad_hodin = 24
99
- elif "oprava" in text_zadani.lower():
100
- odhad_hodin = 4
101
-
102
- cena_prace = odhad_hodin * hodinova_sazba
103
  cena_materialu = round(cena_prace * 0.65, 2)
104
- celkova_cena = cena_prace + cena_materialu
105
 
106
- quote_id = len(st.session_state.db_quotes) + 1
107
  quote_data = {
108
- "id": quote_id,
109
- "zakaznik": customer_name,
110
- "popis": text_zadani,
111
- "hodin": odhad_hodin,
112
- "cena_prace": cena_prace,
113
- "cena_mat": cena_materialu,
114
- "celkem": celkova_cena,
115
- "datum": time.strftime("%Y-%m-%d")
116
  }
117
-
118
  st.session_state.db_quotes.append(quote_data)
119
  st.session_state.quotes_count += 1
120
  return quote_data
121
  except Exception as e:
122
- log_system_error(f"Chyba AI generátoru: {str(e)}", traceback.format_exc())
123
  return None
124
 
125
  # -----------------------------------------------------------------------------
126
- # UI STRUKTURA (STREAMLIT INTERFACE)
127
  # -----------------------------------------------------------------------------
128
- st.title("🏆 TradeFlow AI")
129
- st.caption(f"Chytrý operační systém pro novou generaci řemeslníků a živnostníků. Běží na verzi: {VERSION}")
130
-
131
- # Globální chybová konzole viditelná ihned při selhání kódu
132
- if st.session_state.error_logs:
133
- with st.expander("⚠️ SYSTÉMOVÝ DEBBUG LOG (Přepošli vývojáři k opravě)", expanded=True):
134
- for log in st.session_state.error_logs:
135
- st.error(f"**[{log['time']}]** {log['msg']}")
136
- st.code(log['trace'], language="python")
137
- if st.button("Vyčistit systémové logy"):
138
- st.session_state.error_logs = []
139
- st.rerun()
140
-
141
- # BOČNÍ PANEL: SPRÁVA CHOVÁNÍ APLIKACE A EMULACE
142
  with st.sidebar:
143
- st.header("🛠️ Dev Panel pro Testování")
144
- st.session_state.dev_mode = st.checkbox("Aktivovat testovací nástroje", value=st.session_state.dev_mode)
 
 
 
 
145
 
146
- if st.session_state.dev_mode:
147
- st.markdown("---")
148
- st.subheader("Stav účtu a Limity")
 
 
 
 
 
 
 
 
149
  st.session_state.user_subscribed = st.toggle("Uživatel má zakoupen PRO tarif", value=st.session_state.user_subscribed)
150
- st.session_state.quotes_count = st.number_input("Počet vygenerovaných nabídek v tomto měsíci", min_value=0, max_value=10, value=st.session_state.quotes_count)
151
-
152
- st.markdown("---")
153
- st.subheader("Stripe Gateway Config")
154
  st.session_state.stripe_mode = st.radio("Režim Stripe", ["Sandbox (Simulace)", "Stripe Live API"])
155
  if st.session_state.stripe_mode == "Stripe Live API":
156
- st.session_state.stripe_api_key = st.text_input("Vlož sk_live_...", type="password", value=st.session_state.stripe_api_key)
157
-
158
- st.markdown("---")
159
- if st.button("Resetovat aplikaci do výchozího stavu"):
 
 
160
  st.session_state.clear()
161
  st.rerun()
162
 
163
- # Kontrola překročení limitů bez předplatného
 
 
 
 
 
 
 
 
164
  is_locked = st.session_state.quotes_count >= 3 and not st.session_state.user_subscribed
165
 
166
- # Rozdělení rozhraní na logické sekce pomocí záložek
167
- tab_dashboard, tab_generator, tab_crm, tab_fakturace = st.tabs([
168
- "📈 Přehled & Metriky",
169
- "📝 AI Generátor Nabídek",
170
- "👥 Adresář (CRM Lite)",
171
- "🧾 Fakturace jedním klikem"
172
  ])
173
 
174
- # ZÁLOŽKA 1: AKTUÁLNÍ PODNIKATELSKÉ VÝSLEDKY
175
  with tab_dashboard:
176
- st.header("Podnikání pod kontrolou")
177
- try:
178
- total_revenue = sum(inv["castka"] for inv in st.session_state.db_invoices if inv["stav"] == "Zaplaceno")
179
- pending_revenue = sum(inv["castka"] for inv in st.session_state.db_invoices if inv["stav"] == "Odesláno")
180
- potencial = sum(q["celkem"] for q in st.session_state.db_quotes)
181
-
182
- c1, c2, c3, c4 = st.columns(4)
183
- c1.metric("Skutečný zisk (Zaplaceno)", f"{total_revenue:,.2f} EUR")
184
- c2.metric("Čekající peníze (Ve fakturách)", f"{pending_revenue:,.2f} EUR")
185
- c3.metric("Otevřené AI Nabídky (Potenciál)", f"{potencial:,.2f} EUR")
186
- c4.metric("Využití Free limitu", f"{st.session_state.quotes_count} / 3", delta="⚠️ LIMIT DOSAŽEN" if is_locked else "V normě")
187
-
188
- st.subheader("Přehled posledních aktivit")
189
- if not st.session_state.db_quotes:
190
- st.info("Zatím jste nevygenerovali žádnou cenovou nabídku. Začněte v záložce AI Generátor.")
191
- else:
192
- df_overview = pd.DataFrame(st.session_state.db_quotes)
193
- st.dataframe(df_overview[["datum", "zakaznik", "popis", "celkem"]], use_container_width=True)
194
- except Exception as e:
195
- log_system_error(f"Chyba vykreslení dashboardu: {str(e)}", traceback.format_exc())
196
 
197
- # ZÁLOŽKA 2: GENEROVÁNÍ NABÍDEK A STRIPE PAYWALL
198
  with tab_generator:
199
- st.header("Vytvoření nabídky pomocí AI")
200
-
201
  if is_locked:
202
- st.error("🔒 Dosáhli jste limitu 3 bezplatných nabídek pro tento měsíc. Pro neomezené generování aktivujte tarif PRO níže.")
203
-
204
  col_pay_form, col_pay_info = st.columns([1.5, 1])
205
  with col_pay_form:
206
- with st.form("stripe_paywall_form"):
207
- st.subheader("Aktivace TradeFlow PRO")
208
- st.write("**Cena:** 29.00 / měsíčně (Bez závazků)")
209
- cc_num = st.text_input("Číslo karty", value="4242 4242 4242 4242")
210
- cc_m = st.selectbox("Měsíc", [f"{i:02d}" for i in range(1, 13)], index=5)
211
- cc_y = st.selectbox("Rok", [str(i) for i in range(2026, 2035)], index=0)
212
  cc_cvc = st.text_input("CVC", value="123")
213
-
214
- pay_submit = st.form_submit_button("Bezpečně zaplatit €29.00", use_container_width=True)
215
- if pay_submit:
216
- with st.spinner("Zpracovávám platbu..."):
217
- success, msg = execute_stripe_checkout(cc_num, cc_m, cc_y, cc_cvc)
218
- if success:
219
- st.success(msg)
220
- time.sleep(0.5)
221
- st.rerun()
222
- else:
223
- st.error(msg)
224
- with col_pay_info:
225
- st.markdown("""
226
- ### Co získáte s tarifem PRO:
227
- * **Neomezené** AI generování komplexních kalkulací.
228
- * **Fakturace 1 kliknutím** přímo z vygenerované nabídky.
229
- * Možnost stahovat dokumenty pro zákazníky v čistém formátu.
230
- """)
231
  else:
232
- try:
233
- with st.form("ai_generator_form"):
234
- cust_names = [c["jmeno"] for c in st.session_state.db_customers]
235
- selected_cust = st.selectbox("Vyberte zákazníka z adresáře", cust_names)
236
- input_task = st.text_area("Popište práci vlastními slovy",
237
- value="Kompletní rekonstrukce koupelny v panelovém bytě. Vybourání starého jádra, nové obklady, montáž sprchového koutu, instalace baterie a napojení pračky.")
238
- hourly_rate = st.number_input("Vaše hodinová sazba za práci (EUR/hod)", min_value=10, max_value=250, value=35)
239
-
240
- submit_ai = st.form_submit_button("⚡ Vygenerovat profesionální rozpočet pomocí AI")
241
-
242
- if submit_ai:
243
- with st.spinner("AI TradeFlow přepočítává normohodiny a sestavuje položkový rozpočet..."):
244
- new_quote = mock_ai_generate_quote(selected_cust, input_task, hourly_rate)
245
- if new_quote:
246
- st.success("Cenová nabídka byla úspěšně vygenerována a uložena!")
247
- st.markdown(f"### 📄 CENOVÁ NABÍDKA PRO: {new_quote['zakaznik'].upper()}")
248
- st.markdown(f"**Datum vystavení:** {new_quote['datum']} | **Status:** Návrh")
249
- st.markdown("---")
250
- st.write(f"**Specifikace díla:** {new_quote['popis']}")
251
-
252
- df_items = pd.DataFrame([
253
- {"Položka": "Odborné řemeslné práce", "Množství": f"{new_quote['hodin']} hod", "Sazba": f"{hourly_rate} EUR/hod", "Cena celkem": f"{new_quote['cena_prace']:.2f} EUR"},
254
- {"Položka": "Spotřební a stavební materiál", "Množství": "Paušál", "Sazba": "Dle projektu", "Cena celkem": f"{new_quote['cena_mat']:.2f} EUR"}
255
- ])
256
- st.table(df_items)
257
- st.markdown(f"### **KONEČNÁ CENA K ÚHRADĚ: {new_quote['celkem']:.2f} EUR**")
258
- except Exception as e:
259
- log_system_error(f"Chyba formuláře generátoru: {str(e)}", traceback.format_exc())
260
 
261
- # ZÁLOŽKA 3: ADRESÁŘ ZÁKAZNÍKŮ (CRM LITE)
262
  with tab_crm:
263
- st.header("Adresář zákazníků")
264
- try:
265
- col_crm_list, col_crm_add = st.columns([2, 1])
266
-
267
- with col_crm_list:
268
- st.subheader("Aktuální klienti")
269
- if not st.session_state.db_customers:
270
- st.info("Adresář je prázdný.")
271
- else:
272
- df_cust = pd.DataFrame(st.session_state.db_customers)
273
- st.dataframe(df_cust[["jmeno", "firma", "telefon"]], use_container_width=True)
274
-
275
- with col_crm_add:
276
- st.subheader("Nový zákazník")
277
- with st.form("add_customer_form"):
278
- new_name = st.text_input("Jméno a příjmení")
279
- new_company = st.text_input("Firma / Název společnosti (Volitelné)")
280
- new_phone = st.text_input("Telefonní číslo")
281
- crm_submit = st.form_submit_button("Uložit klienta")
282
-
283
- if crm_submit:
284
- if not new_name:
285
- st.error("Jméno klienta je povinné.")
286
- else:
287
- st.session_state.db_customers.append({
288
- "id": len(st.session_state.db_customers) + 1,
289
- "jmeno": new_name,
290
- "firma": new_company if new_company else "Fyzická osoba",
291
- "telefon": new_phone
292
- })
293
- st.success("Klient byl úspěšně přidán do CRM.")
294
- st.rerun()
295
- except Exception as e:
296
- log_system_error(f"Chyba v CRM subsystému: {str(e)}", traceback.format_exc())
297
 
298
- # ZÁLOŽKA 4: KONVERZE NABÍDKY NA FAKTURY
299
  with tab_fakturace:
300
- st.header("Fakturace schválených zakázek")
301
- try:
302
- if not st.session_state.db_quotes:
303
- st.info("Nemáte žádné vygenerované cenové nabídky, ze kterých by bylo možné vytvořit fakturu.")
304
- else:
305
- st.subheader("Převést schválenou nabídku na fakturu (1 kliknutí)")
306
- quote_options = {f"ID: {q['id']} | {q['zakaznik']} — {q['celkem']:.2f} EUR": q for q in st.session_state.db_quotes}
307
- selected_quote_label = st.selectbox("Zvolte cenovou nabídku pro fakturaci", list(quote_options.keys()))
308
- chosen_quote = quote_options[selected_quote_label]
309
-
310
- if st.button("🧾 VYSTAVIT FAKTURU JEDNÍM KLIKNUTÍM", type="primary", use_container_width=True):
311
- invoice_id = len(st.session_state.db_invoices) + 1
312
- new_invoice = {
313
- "id": invoice_id,
314
- "cislo": f"2026{invoice_id:04d}",
315
- "zakaznik": chosen_quote["zakaznik"],
316
- "castka": chosen_quote["celkem"],
317
- "stav": "Odesláno",
318
- "datum": time.strftime("%Y-%m-%d")
319
- }
320
- st.session_state.db_invoices.append(new_invoice)
321
- st.success(f"Faktura číslo {new_invoice['cislo']} byla úspěšně vystavena a odeslána na e-mail klienta.")
322
 
323
- st.markdown("---")
324
- st.subheader("Přehled vystavených faktur")
325
- if not st.session_state.db_invoices:
326
- st.caption("Zatím nebyly vystaveny žádné faktury.")
327
- else:
328
- for idx, inv in enumerate(st.session_state.db_invoices):
329
- c_inv1, c_inv2, c_inv3, c_inv4 = st.columns([1, 2, 1, 1])
330
- c_inv1.write(f"**FA {inv['cislo']}**")
331
- c_inv2.write(f"Klient: {inv['zakaznik']} | Částka: **{inv['castka']:.2f} EUR**")
332
- stav_barvy = "🟢" if inv["stav"] == "Zaplaceno" else "🔵"
333
- c_inv3.write(f"{stav_barvy} {inv['stav']}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
- if inv["stav"] == "Odesláno":
336
- if c_inv4.button("Označit jako zaplacené", key=f"pay_btn_{idx}"):
337
- inv["stav"] = "Zaplaceno"
338
- st.rerun()
339
- else:
340
- c_inv4.write(" Vyřízeno")
341
-
342
- except Exception as e:
343
- log_system_error(f"Chyba ve fakturačním modulu: {str(e)}", traceback.format_exc())
 
 
 
 
 
 
 
 
 
5
  import random
6
  import traceback
7
 
8
+ # -----------------------------------------------------------------------------
9
+ # JAZYKOVÉ LOKALIZACE (CZ, SK, DE, EN, ES, IT, FR)
10
+ # -----------------------------------------------------------------------------
11
+ TRANSLATIONS = {
12
+ "CZ": {
13
+ "title": "🏆 TradeFlow AI", "caption": "Chytrý operační systém pro novou generaci řemeslníků.",
14
+ "tab_dash": "📈 Přehled & Metriky", "tab_gen": "📝 AI Generátor Nabídek", "tab_crm": "👥 Adresář (CRM)", "tab_inv": "🧾 Fakturace jedním klikem", "tab_pro": "🚀 PRO Exkluzivní Funkce",
15
+ "profit": "Skutečný zisk", "pending": "Čekající peníze", "potential": "Otevřené AI Nabídky", "limit": "Využití Free limitu",
16
+ "cust_name": "Jméno a příjmení", "company": "Firma (Volitelné)", "phone": "Telefonní číslo", "save_cust": "Uložit klienta",
17
+ "hourly_rate": "Vaše hodinová sazba za práci", "generate_btn": "⚡ Vygenerovat rozpočet pomocí AI", "invoice_btn": "🧾 VYSTAVIT FAKTURU JEDNÍM KLIKNUTÍM",
18
+ "paywall_msg": "🔒 Dosáhli jste limitu 3 bezplatných nabídek. Pro neomezený přístup aktivujte tarif PRO.",
19
+ "pro_router": "📍 AI Plánovač tras a logistiky", "pro_sms": "📲 Automatické SMS upomínky neplatičům"
20
+ },
21
+ "SK": {
22
+ "title": "🏆 TradeFlow AI", "caption": "Chytry operačný systém pre novú generáciu remeselníkov.",
23
+ "tab_dash": "📈 Prehľad & Metriky", "tab_gen": "📝 AI Generátor Ponúk", "tab_crm": "👥 Adresár (CRM)", "tab_inv": "🧾 Fakturácia jedným klikom", "tab_pro": "🚀 PRO Exkluzívne Funkcie",
24
+ "profit": "Skutočný zisk", "pending": "Čakajúce peniaze", "potential": "Otvorené AI Ponuky", "limit": "Využitie Free limitu",
25
+ "cust_name": "Meno a priezvisko", "company": "Firma (Voliteľné)", "phone": "Telefónne číslo", "save_cust": "Uložiť klienta",
26
+ "hourly_rate": "Vaša hodinová sadzba za prácu", "generate_btn": "⚡ Vygenerovať rozpočet pomocou AI", "invoice_btn": "🧾 VYSTAVIŤ FAKTÚRU JEDNÝM KLIKNUTÍM",
27
+ "paywall_msg": "🔒 Dosiahli ste limitu 3 bezplatných ponúk. Pre neobmedzený prístup aktivujte tarif PRO.",
28
+ "pro_router": "📍 AI Plánovač trás a logistiky", "pro_sms": "📲 Automatické SMS upomienky neplatičom"
29
+ },
30
+ "EN": {
31
+ "title": "🏆 TradeFlow AI", "caption": "Smart operating system for the next-gen skilled trades.",
32
+ "tab_dash": "📈 Dashboard & Metrics", "tab_gen": "📝 AI Quote Generator", "tab_crm": "👥 Contacts (CRM)", "tab_inv": "🧾 1-Click Invoicing", "tab_pro": "🚀 PRO Features",
33
+ "profit": "Actual Profit", "pending": "Pending Revenue", "potential": "Open AI Quotes", "limit": "Free Tier Usage",
34
+ "cust_name": "Full Name", "company": "Company (Optional)", "phone": "Phone Number", "save_cust": "Save Client",
35
+ "hourly_rate": "Your hourly labor rate", "generate_btn": "⚡ Generate Professional Quote via AI", "invoice_btn": "🧾 ISSUE 1-CLICK INVOICE",
36
+ "paywall_msg": "🔒 You have reached the 3 free quotes limit. Unlock PRO tier for unlimited access.",
37
+ "pro_router": "📍 AI Route & Logistics Planner", "pro_sms": "📲 Automated SMS Reminders for Overdue Invoices"
38
+ },
39
+ "DE": {
40
+ "title": "🏆 TradeFlow AI", "caption": "Intelligentes Betriebssystem für Handwerker.",
41
+ "tab_dash": "📈 Dashboard & Metriken", "tab_gen": "📝 AI-Angebotsgenerator", "tab_crm": "👥 Kontakte (CRM)", "tab_inv": "🧾 1-Klick-Rechnungsstellung", "tab_pro": "🚀 PRO-Funktionen",
42
+ "profit": "Tatsächlicher Gewinn", "pending": "Ausstehende Einnahmen", "potential": "Offene KI-Angebote", "limit": "Free-Tier-Nutzung",
43
+ "cust_name": "Vollständiger Name", "company": "Firma (Optional)", "phone": "Telefonnummer", "save_cust": "Kunde speichern",
44
+ "hourly_rate": "Ihr Stundensatz", "generate_btn": "⚡ KI-Angebot generieren", "invoice_btn": "🧾 1-KLICK-RECHNUNG ERSTELLEN",
45
+ "paywall_msg": "🔒 Sie haben das Limit von 3 kostenlosen Angeboten erreicht. Aktivieren Sie PRO.",
46
+ "pro_router": "📍 KI-Routen- & Logistikplaner", "pro_sms": "📲 Automatische SMS-Mahnungen senden"
47
+ },
48
+ "SPA": {
49
+ "title": "🏆 TradeFlow AI", "caption": "Sistema operativo inteligente para profesionales de la construcción.",
50
+ "tab_dash": "📈 Panel y Métricas", "tab_gen": "📝 Generador AI de Presupuestos", "tab_crm": "👥 Contactos (CRM)", "tab_inv": "🧾 Facturación en 1 Clic", "tab_pro": "🚀 Funciones PRO",
51
+ "profit": "Ganancia Real", "pending": "Ingresos Pendientes", "potential": "Presupuestos AI Abiertos", "limit": "Uso de Cuenta Free",
52
+ "cust_name": "Nombre Completo", "company": "Empresa (Opcional)", "phone": "Número de Teléfono", "save_cust": "Guardar Cliente",
53
+ "hourly_rate": "Su tarifa por hora", "generate_btn": "⚡ Generar Presupuesto con IA", "invoice_btn": "🧾 GENERAR FACTURA EN 1 CLIC",
54
+ "paywall_msg": "🔒 Ha alcanzado el límite de 3 presupuestos gratis. Active el plan PRO.",
55
+ "pro_router": "📍 Planificador IA de Rutas", "pro_sms": "📲 Recordatorios de Pago Automáticos por SMS"
56
+ },
57
+ "ITA": {
58
+ "title": "🏆 TradeFlow AI", "caption": "Sistema operativo intelligente per artigiani e professionisti.",
59
+ "tab_dash": "📈 Dashboard e Metriche", "tab_gen": "📝 Generatore AI di Preventivi", "tab_crm": "👥 Contatti (CRM)", "tab_inv": "🧾 Fatturazione in 1 Clic", "tab_pro": "🚀 Funzioni PRO",
60
+ "profit": "Profitto Reale", "pending": "Entrate In Sospeso", "potential": "Preventivi AI Aperti", "limit": "Utilizzo Free Tier",
61
+ "cust_name": "Nome Completo", "company": "Azienda (Opzionale)", "phone": "Numero di Telefono", "save_cust": "Salva Cliente",
62
+ "hourly_rate": "La tua tariffa oraria", "generate_btn": "⚡ Genera Preventivo con IA", "invoice_btn": "🧾 GENERA FATTURA IN 1 CLIC",
63
+ "paywall_msg": "🔒 Hai raggiunto il limite di 3 preventivi gratuiti. Attiva il piano PRO.",
64
+ "pro_router": "📍 Pianificatore IA di Rotte", "pro_sms": "📲 Promemoria SMS Automatici di Pagamento"
65
+ },
66
+ "FRA": {
67
+ "title": "🏆 TradeFlow AI", "caption": "Système d'exploitation intelligent pour les artisans.",
68
+ "tab_dash": "📈 Tableau de bord", "tab_gen": "📝 Générateur de Devis IA", "tab_crm": "👥 Contacts (CRM)", "tab_inv": "🧾 Facturation en 1 Clic", "tab_pro": "🚀 Fonctions PRO",
69
+ "profit": "Bénéfice Réel", "pending": "Revenus En Attente", "potential": "Devis IA Ouverts", "limit": "Utilisation Free Tier",
70
+ "cust_name": "Nom Complet", "company": "Entreprise (Optionnel)", "phone": "Numéro de Téléphone", "save_cust": "Enregistrer le Client",
71
+ "hourly_rate": "Votre taux horaire", "generate_btn": "⚡ Générer le Devis via IA", "invoice_btn": "🧾 CRÉER LA FACTURE EN 1 CLIC",
72
+ "paywall_msg": "🔒 Limite de 3 devis gratuits atteinte. Activez l'abonnement PRO.",
73
+ "pro_router": "📍 Planificateur IA d'Itinéraires", "pro_sms": "📲 Relances de Factures Automatiques par SMS"
74
+ }
75
+ }
76
+
77
+ # CONFIGURACE MĚN (Základna je EUR, kurzy jsou orientační pro simulaci přepočtu)
78
+ CURRENCIES = {
79
+ "EUR": {"symbol": "EUR", "rate": 1.0},
80
+ "CZK": {"symbol": "Kč", "rate": 25.12},
81
+ "USD": {"symbol": "$", "rate": 1.09},
82
+ "GBP": {"symbol": "£", "rate": 0.84},
83
+ "CHF": {"symbol": "CHF", "rate": 0.96}
84
+ }
85
+
86
  # -----------------------------------------------------------------------------
87
  # KONFIGURACE A INICIALIZACE STAVU
88
  # -----------------------------------------------------------------------------
89
+ VERSION = "1.2.0-PRODUKČNÍ"
90
 
91
+ st.set_page_config(page_title="TradeFlow AI", page_icon="🏆", layout="wide", initial_sidebar_state="expanded")
92
+
93
+ # Výchozí stavy aplikace
94
+ if "lang" not in st.session_state: st.session_state.lang = "CZ"
95
+ if "curr" not in st.session_state: st.session_state.curr = "EUR"
96
+ if "admin_authenticated" not in st.session_state: st.session_state.admin_authenticated = False
97
+ if "user_subscribed" not in st.session_state: st.session_state.user_subscribed = False
98
+ if "quotes_count" not in st.session_state: st.session_state.quotes_count = 1
99
+ if "stripe_mode" not in st.session_state: st.session_state.stripe_mode = "Sandbox (Simulace)"
100
+ if "stripe_api_key" not in st.session_state: st.session_state.stripe_api_key = ""
101
+ if "error_logs" not in st.session_state: st.session_state.error_logs = []
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  if "db_customers" not in st.session_state:
104
  st.session_state.db_customers = [
105
  {"id": 1, "jmeno": "Jan Novák", "firma": "Stavebniny s.r.o.", "telefon": "+420 777 123 456"},
106
  {"id": 2, "jmeno": "Marie Podlahová", "firma": "Bytové družstvo", "telefon": "+420 602 987 654"}
107
  ]
108
+ if "db_quotes" not in st.session_state: st.session_state.db_quotes = []
109
+ if "db_invoices" not in st.session_state: st.session_state.db_invoices = []
110
+
111
+ # Pomocná funkce pro formátování měny
112
+ def format_price(amount_in_eur):
113
+ c_info = CURRENCIES[st.session_state.curr]
114
+ converted = amount_in_eur * c_info["rate"]
115
+ if c_info["symbol"] in ["Kč", "CHF"]:
116
+ return f"{converted:,.2f} {c_info['symbol']}"
117
+ return f"{c_info['symbol']}{converted:,.2f}"
118
 
119
  def log_system_error(err_msg, trace_str):
120
+ st.session_state.error_logs.append({"time": time.strftime("%H:%M:%S"), "msg": err_msg, "trace": trace_str})
121
+
122
+ # Zkratka pro texty akt. jazyka
123
+ t = TRANSLATIONS[st.session_state.lang]
 
124
 
125
  # -----------------------------------------------------------------------------
126
+ # BACKEND SUBSYSTÉMY (STRIPE & MOCK AI)
127
  # -----------------------------------------------------------------------------
128
  def execute_stripe_checkout(card_number, exp_month, exp_year, cvc, amount=29.00):
129
  try:
130
  if st.session_state.stripe_mode == "Stripe Live API":
131
+ if not st.session_state.stripe_api_key: raise ValueError("Chybí Stripe API klíč.")
 
132
  stripe.api_key = st.session_state.stripe_api_key
133
+ token = stripe.Token.create(card={"number": card_number, "exp_month": int(exp_month), "exp_year": int(exp_year), "cvc": cvc})
134
+ charge = stripe.Charge.create(amount=int(amount * 100), currency="eur", source=token.id, description="TradeFlow AI Pro")
 
 
 
 
 
135
  if charge.status == "succeeded":
136
  st.session_state.user_subscribed = True
137
+ return True, "Platba úspěšná přes Stripe Live API!"
138
+ return False, f"Zamítnuto Stripe: {charge.status}"
139
  else:
 
140
  time.sleep(1.0)
141
+ if not card_number or len(card_number.replace(" ", "")) < 16: return False, "Neplatné číslo karty."
142
+ if cvc == "000": return False, "Karta zamítnuta (Sandbox Kód 51 - Nedostatečný zůstatek)."
 
 
143
  st.session_state.user_subscribed = True
144
+ return True, "Sandbox úspěch: PRO Licence aktivována!"
145
  except Exception as e:
146
+ log_system_error(str(e), traceback.format_exc())
147
+ return False, str(e)
 
148
 
149
+ def mock_ai_generate_quote(customer_name, text_zadani, hodinova_sazba_v_local):
 
 
 
150
  try:
151
  if st.session_state.quotes_count >= 3 and not st.session_state.user_subscribed:
152
+ raise PermissionError("Free tier limit reached.")
 
153
  time.sleep(1.2)
154
+ odhad_hodin = 24 if any(x in text_zadani.lower() for x in ["koupeln", "rekonstrukce", "bath", "renov"]) else 6
155
 
156
+ # Přepočet local hodinové sazby zpět na základní EUR pro uložení do DB
157
+ rate_in_eur = hodinova_sazba_v_local / CURRENCIES[st.session_state.curr]["rate"]
158
+ cena_prace = odhad_hodin * rate_in_eur
 
 
 
 
 
159
  cena_materialu = round(cena_prace * 0.65, 2)
 
160
 
 
161
  quote_data = {
162
+ "id": len(st.session_state.db_quotes) + 1, "zakaznik": customer_name, "popis": text_zadani,
163
+ "hodin": odhad_hodin, "cena_prace": cena_prace, "cena_mat": cena_materialu,
164
+ "celkem": cena_prace + cena_materialu, "datum": time.strftime("%Y-%m-%d")
 
 
 
 
 
165
  }
 
166
  st.session_state.db_quotes.append(quote_data)
167
  st.session_state.quotes_count += 1
168
  return quote_data
169
  except Exception as e:
170
+ log_system_error(str(e), traceback.format_exc())
171
  return None
172
 
173
  # -----------------------------------------------------------------------------
174
+ # SIDEBAR: NASTAVENÍ JAZYKA, MĚNY A CHRÁNĚNÝ ADMIN PANEL
175
  # -----------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  with st.sidebar:
177
+ st.header("🌐 Nastavení / Settings")
178
+ st.session_state.lang = st.selectbox("Language / Jazyk", list(TRANSLATIONS.keys()), index=list(TRANSLATIONS.keys()).index(st.session_state.lang))
179
+ st.session_state.curr = st.selectbox("Měna / Currency", list(CURRENCIES.keys()), index=list(CURRENCIES.keys()).index(st.session_state.curr))
180
+
181
+ st.markdown("---")
182
+ st.header("🛡️ Dev Admin Panel")
183
 
184
+ if not st.session_state.admin_authenticated:
185
+ pwd_input = st.text_input("Zadejte administrátorské heslo", type="password", help="Heslo pro porotu/vývojáře je: admin123")
186
+ if st.button("Odemknout Admin Panel"):
187
+ if pwd_input == "admin123":
188
+ st.session_state.admin_authenticated = True
189
+ st.success("Přístup udělen!")
190
+ st.rerun()
191
+ else:
192
+ st.error("Nesprávné heslo!")
193
+ else:
194
+ st.info("🔓 Úspěšně autorizováno")
195
  st.session_state.user_subscribed = st.toggle("Uživatel má zakoupen PRO tarif", value=st.session_state.user_subscribed)
196
+ st.session_state.quotes_count = st.number_input("Počet vygenerovaných nabídek", min_value=0, max_value=10, value=st.session_state.quotes_count)
 
 
 
197
  st.session_state.stripe_mode = st.radio("Režim Stripe", ["Sandbox (Simulace)", "Stripe Live API"])
198
  if st.session_state.stripe_mode == "Stripe Live API":
199
+ st.session_state.stripe_api_key = st.text_input("Stripe Secret Key", type="password", value=st.session_state.stripe_api_key)
200
+
201
+ if st.button("Zamknout panel & Odhlásit se"):
202
+ st.session_state.admin_authenticated = False
203
+ st.rerun()
204
+ if st.button("Resetovat kompletní aplikaci"):
205
  st.session_state.clear()
206
  st.rerun()
207
 
208
+ # Aktualizace textů po případné změně jazyka v sidebar
209
+ t = TRANSLATIONS[st.session_state.lang]
210
+
211
+ st.title(t["title"])
212
+ st.caption(f"{t['caption']} | Version: {VERSION}")
213
+
214
+ # -----------------------------------------------------------------------------
215
+ # HLAVNÍ ROZHRANÍ (TABS)
216
+ # -----------------------------------------------------------------------------
217
  is_locked = st.session_state.quotes_count >= 3 and not st.session_state.user_subscribed
218
 
219
+ tab_dashboard, tab_generator, tab_crm, tab_fakturace, tab_pro_features = st.tabs([
220
+ t["tab_dash"], t["tab_gen"], t["tab_crm"], t["tab_inv"], t["tab_pro"]
 
 
 
 
221
  ])
222
 
223
+ # TAB 1: METRIKY A PŘEHLED
224
  with tab_dashboard:
225
+ st.header(t["tab_dash"])
226
+ total_revenue = sum(inv["castka"] for inv in st.session_state.db_invoices if inv["stav"] == "Zaplaceno")
227
+ pending_revenue = sum(inv["castka"] for inv in st.session_state.db_invoices if inv["stav"] == "Odesláno")
228
+ potencial = sum(q["celkem"] for q in st.session_state.db_quotes)
229
+
230
+ c1, c2, c3, c4 = st.columns(4)
231
+ c1.metric(t["profit"], format_price(total_revenue))
232
+ c2.metric(t["pending"], format_price(pending_revenue))
233
+ c3.metric(t["potential"], format_price(potencial))
234
+ c4.metric(t["limit"], f"{st.session_state.quotes_count} / 3", delta="⚠️ LIMIT" if is_locked else None)
235
+
236
+ st.subheader("Aktivity")
237
+ if st.session_state.db_quotes:
238
+ df_raw = pd.DataFrame(st.session_state.db_quotes)
239
+ df_display = df_raw.copy()
240
+ df_display["celkem"] = df_display["celkem"].apply(format_price)
241
+ st.dataframe(df_display[["datum", "zakaznik", "popis", "celkem"]], use_container_width=True)
242
+ else:
243
+ st.info("Žádná data k zobrazení.")
 
244
 
245
+ # TAB 2: AI GENERÁTOR & PAYWALL
246
  with tab_generator:
247
+ st.header(t["tab_gen"])
 
248
  if is_locked:
249
+ st.error(t["paywall_msg"])
 
250
  col_pay_form, col_pay_info = st.columns([1.5, 1])
251
  with col_pay_form:
252
+ with st.form("stripe_form_updated"):
253
+ st.subheader("TradeFlow PRO Sub")
254
+ st.write(f"Cena: {format_price(29.00)} / měsíčně")
255
+ cc_num = st.text_input("Card Number", value="4242 4242 4242 4242")
256
+ cc_m = st.selectbox("Month", [f"{i:02d}" for i in range(1, 13)], index=5)
257
+ cc_y = st.selectbox("Year", [str(i) for i in range(2026, 2035)], index=0)
258
  cc_cvc = st.text_input("CVC", value="123")
259
+ if st.form_submit_button("Pay & Activate PRO"):
260
+ success, msg = execute_stripe_checkout(cc_num, cc_m, cc_y, cc_cvc)
261
+ if success: st.success(msg); time.sleep(0.5); st.rerun()
262
+ else: st.error(msg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  else:
264
+ with st.form("ai_generator_form"):
265
+ cust_names = [c["jmeno"] for c in st.session_state.db_customers]
266
+ selected_cust = st.selectbox("Klient / Client", cust_names if cust_names else ["-"])
267
+ input_task = st.text_area("Zadání práce / Task description", value="Rekonstrukce koupelny, montáž vany a obklady.")
268
+
269
+ # Dynamické zobrazení hodinové sazby v aktuálně zvolené měně
270
+ current_rate_multiplier = CURRENCIES[st.session_state.curr]["rate"]
271
+ local_hourly_rate = st.number_input(f"{t['hourly_rate']} ({CURRENCIES[st.session_state.curr]['symbol']}/hod)",
272
+ min_value=10, max_value=5000, value=int(35 * current_rate_multiplier))
273
+
274
+ if st.form_submit_button(t["generate_btn"]):
275
+ res = mock_ai_generate_quote(selected_cust, input_task, local_hourly_rate)
276
+ if res:
277
+ st.success("AI Success!")
278
+ st.markdown(f"### Devis / Quote: {res['zakaznik'].upper()}")
279
+ st.write(f"**Popis:** {res['popis']}")
280
+ st.write(f"**Práce:** {res['hodin']} hod -> {format_price(res['cena_prace'])}")
281
+ st.write(f"**Materiál:** {format_price(res['cena_mat'])}")
282
+ st.markdown(f"## **Celkem k úhradě: {format_price(res['celkem'])}**")
 
 
 
 
 
 
 
 
 
283
 
284
+ # TAB 3: CRM LITE
285
  with tab_crm:
286
+ st.header(t["tab_crm"])
287
+ col1, col2 = st.columns([2, 1])
288
+ with col1:
289
+ if st.session_state.db_customers:
290
+ st.dataframe(pd.DataFrame(st.session_state.db_customers)[["jmeno", "firma", "telefon"]], use_container_width=True)
291
+ with col2:
292
+ with st.form("add_crm"):
293
+ n = st.text_input(t["cust_name"])
294
+ f = st.text_input(t["company"])
295
+ p = st.text_input(t["phone"])
296
+ if st.form_submit_button(t["save_cust"]) and n:
297
+ st.session_state.db_customers.append({"id": len(st.session_state.db_customers)+1, "jmeno": n, "firma": f if f else "Fyzická osoba", "telefon": p})
298
+ st.success("Saved"); time.sleep(0.3); st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
+ # TAB 4: FAKTURACE
301
  with tab_fakturace:
302
+ st.header(t["tab_inv"])
303
+ if not st.session_state.db_quotes:
304
+ st.info("Žádné nabídky k fakturaci.")
305
+ else:
306
+ quote_options = {f"ID: {q['id']} | {q['zakaznik']} — {format_price(q['celkem'])}": q for q in st.session_state.db_quotes}
307
+ selected_quote_label = st.selectbox("Vyberte zakázku", list(quote_options.keys()))
308
+ chosen_quote = quote_options[selected_quote_label]
309
+
310
+ if st.button(t["invoice_btn"], type="primary", use_container_width=True):
311
+ st.session_state.db_invoices.append({
312
+ "id": len(st.session_state.db_invoices)+1, "cislo": f"2026{len(st.session_state.db_invoices)+1:04d}",
313
+ "zakaznik": chosen_quote["zakaznik"], "castka": chosen_quote["celkem"], "stav": "Odesláno", "datum": time.strftime("%Y-%m-%d")
314
+ })
315
+ st.success("Faktura odeslána!")
 
 
 
 
 
 
 
 
316
 
317
+ st.markdown("---")
318
+ for idx, inv in enumerate(st.session_state.db_invoices):
319
+ cx1, cx2, cx3 = st.columns([2, 1, 1])
320
+ cx1.write(f"**FA {inv['cislo']}** {inv['zakaznik']} ({format_price(inv['castka'])})")
321
+ cx2.write("🟢 Zaplaceno" if inv["stav"] == "Zaplaceno" else "🔵 Odesláno")
322
+ if inv["stav"] == "Odesláno" and cx3.button("Smazat dluh (Zaplaceno)", key=f"p_btn_{idx}"):
323
+ inv["stav"] = "Zaplaceno"
324
+ st.rerun()
325
+
326
+ # -----------------------------------------------------------------------------
327
+ # TAB 5: 🚀 BONUS PRO EXKLUZIVNÍ FUNKCE (ZAMČENO/ODEMČENO)
328
+ # -----------------------------------------------------------------------------
329
+ with tab_pro_features:
330
+ st.header(t["tab_pro"])
331
+
332
+ if not st.session_state.user_subscribed:
333
+ st.warning("🔒 Tato sekce obsahuje exkluzivní prémiové nástroje, které jsou dostupné pouze pro uživatele s aktivovaným tarifem TradeFlow PRO.")
334
+ st.markdown("""
335
+ ### Co se zde skrývá?
336
+ 1. **AI Smart Router:** Zadejte adresy svých zakázek a naše AI spočítá nejefektivnější logistickou trasu, čímž ušetříte až 20% nákladů na palivo.
337
+ 2. **Auto-Reminders:** Systém automaticky hlídá splatnost faktur a neplatičům posílá personalizované SMS upomínky přes integrovanou SMS bránu.
338
+
339
+ *Tip: Odemkněte PRO tarif v bočním Dev panelu nebo projděte Stripe testovací platební bránou v záložce generátoru.*
340
+ """)
341
+ else:
342
+ st.balloons()
343
+ st.success("🌟 Vítejte v zóně TradeFlow PRO! Máte plný přístup k enterprise modulům.")
344
+
345
+ p_subtab1, p_subtab2 = st.tabs([t["pro_router"], t["pro_sms"]])
346
+
347
+ with p_subtab1:
348
+ st.subheader("Optimalizace ranních výjezdů za klienty")
349
+ st.caption("AI engine analyzuje ranní zácpy a polohu skladů stavebního materiálu.")
350
+ addresses = st.text_area("Zadejte adresy zakázek (jedna na řádek)",
351
+ value="Plzeňská 15, Praha\nPrůmyslová 4, Beroun\nSukova 12, Plzeň")
352
+ if st.button("🗺️ Spočítat nejkratší trasu s úsporou paliva"):
353
+ with st.spinner("AI optimalizuje logistický řetězec..."):
354
+ time.sleep(1.5)
355
+ st.info("🚀 **AI Výsledek:** Optimální pořadí: *Beroun -> Praha -> Plzeň*. Celková úspora: **42 km** (cca 310 Kč na palivu) a **35 minut** čistého času řemeslníka.")
356
 
357
+ with p_subtab2:
358
+ st.subheader("Automatické upomínání neplatičů")
359
+ st.caption("Modul napojený na Twilio SMS API odesílá přátelské, ale důrazné upozornění.")
360
+
361
+ overdue_count = sum(1 for inv in st.session_state.db_invoices if inv["stav"] == "Odesláno")
362
+ st.metric("Aktuální počet neplatičů v systému", f"{overdue_count} klienti")
363
+
364
+ sms_template = st.text_area("Šablona SMS zprávy",
365
+ value="Dobrý den, evidujeme, že faktura číslo {cislo} na částku {castka} je po splatnosti. Prosíme o neprodlené uhrazení. Tým TradeFlow AI.")
366
+
367
+ if st.button("📲 Odeslat hromadné SMS upomínky"):
368
+ if overdue_count == 0:
369
+ st.info("Skvělé! Žádný z vašich klientů aktuálně nedluží peníze.")
370
+ else:
371
+ with st.spinner("Odesílám dávku SMS zpráv přes API gateway..."):
372
+ time.sleep(1.0)
373
+ st.success(f"Všech {overdue_count} SMS zpráv bylo úspěšně doručeno na telefony zákazníků.")