z230
This commit is contained in:
172
40 fio 01.py
Normal file
172
40 fio 01.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Import Fio banka CSV export (UTF-8, ; separated, quoted)
|
||||||
|
into MySQL database `fio.transactions`.
|
||||||
|
|
||||||
|
- Datum je vždy ve formátu dd.mm.yyyy.
|
||||||
|
- Přidává diagnostický fingerprint do sloupce `uniq_fp` (indexovaný).
|
||||||
|
- Zatím NEblokuje duplicity; jen je snadno zobrazí pro ladění.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
import pymysql
|
||||||
|
from pymysql.cursors import DictCursor
|
||||||
|
|
||||||
|
# ======== CONFIG ========
|
||||||
|
CSV_PATH = Path(r"u:\Dropbox\!!!Days\Downloads Z230\Vyhledane pohyby (1).csv")
|
||||||
|
TABLE_NAME = "transactions"
|
||||||
|
|
||||||
|
MYSQL_CONFIG = {
|
||||||
|
"host": "192.168.1.76",
|
||||||
|
"port": 3307,
|
||||||
|
"user": "root",
|
||||||
|
"password": "Vlado9674+",
|
||||||
|
"database": "fio",
|
||||||
|
"charset": "utf8mb4",
|
||||||
|
"cursorclass": DictCursor,
|
||||||
|
"autocommit": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------- helpers ----------
|
||||||
|
def clean(s: str):
|
||||||
|
"""Normalize text for consistent comparison (trim + lowercase)."""
|
||||||
|
if not s:
|
||||||
|
return None
|
||||||
|
s = s.strip().lower()
|
||||||
|
return s or None
|
||||||
|
|
||||||
|
def build_fingerprint(data: dict) -> str:
|
||||||
|
"""Sestaví diagnostický fingerprint z normalizovaných polí."""
|
||||||
|
parts = [
|
||||||
|
data["datum"].strftime("%Y-%m-%d") if data["datum"] else "",
|
||||||
|
f"{data['objem']:.2f}" if data["objem"] is not None else "",
|
||||||
|
data.get("cislo_uctu") or "",
|
||||||
|
data.get("protiucet") or "",
|
||||||
|
data.get("kod_banky") or "",
|
||||||
|
data.get("vs") or "",
|
||||||
|
(data.get("zprava") or "")[:100],
|
||||||
|
(data.get("poznamka") or "")[:100],
|
||||||
|
]
|
||||||
|
return "|".join(parts)
|
||||||
|
|
||||||
|
# ======== DB SETUP ========
|
||||||
|
def get_mysql_connection():
|
||||||
|
return pymysql.connect(**MYSQL_CONFIG)
|
||||||
|
|
||||||
|
def ensure_table_exists(conn):
|
||||||
|
sql_create = f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `{TABLE_NAME}` (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
datum DATE,
|
||||||
|
objem DECIMAL(12,2),
|
||||||
|
mena CHAR(3),
|
||||||
|
cislo_uctu VARCHAR(40),
|
||||||
|
protiucet VARCHAR(40),
|
||||||
|
kod_banky VARCHAR(20),
|
||||||
|
ks VARCHAR(20),
|
||||||
|
vs VARCHAR(20),
|
||||||
|
ss VARCHAR(20),
|
||||||
|
zprava VARCHAR(500),
|
||||||
|
poznamka VARCHAR(500),
|
||||||
|
uniq_fp VARCHAR(512),
|
||||||
|
imported_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
"""
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sql_create)
|
||||||
|
|
||||||
|
# ✅ přidej sloupec pouze pokud chybí
|
||||||
|
cur.execute(f"SHOW COLUMNS FROM `{TABLE_NAME}` LIKE 'uniq_fp'")
|
||||||
|
if not cur.fetchone():
|
||||||
|
cur.execute(f"ALTER TABLE `{TABLE_NAME}` ADD COLUMN uniq_fp VARCHAR(512) NULL")
|
||||||
|
print("🆕 Sloupec uniq_fp přidán.")
|
||||||
|
|
||||||
|
# ✅ vytvoř index pokud ještě není
|
||||||
|
cur.execute(f"SHOW INDEX FROM `{TABLE_NAME}` WHERE Key_name = 'idx_uniq_fp'")
|
||||||
|
if not cur.fetchone():
|
||||||
|
cur.execute(f"CREATE INDEX idx_uniq_fp ON `{TABLE_NAME}` (uniq_fp)")
|
||||||
|
print("🆕 Index idx_uniq_fp vytvořen.")
|
||||||
|
|
||||||
|
print("✅ Tabulka a index zkontrolovány.")
|
||||||
|
|
||||||
|
# ======== IMPORT ========
|
||||||
|
def import_fio_csv():
|
||||||
|
with open(CSV_PATH, "r", encoding="utf-8-sig", newline="") as f:
|
||||||
|
reader = csv.DictReader(f, delimiter=";", quotechar='"')
|
||||||
|
rows = list(reader)
|
||||||
|
|
||||||
|
with get_mysql_connection() as conn:
|
||||||
|
ensure_table_exists(conn)
|
||||||
|
inserted = 0
|
||||||
|
|
||||||
|
for row in rows:
|
||||||
|
# --- DATUM ---
|
||||||
|
raw_date = (row.get("Datum") or "").strip()
|
||||||
|
try:
|
||||||
|
datum = datetime.strptime(raw_date, "%d.%m.%Y").date() if raw_date else None
|
||||||
|
except ValueError:
|
||||||
|
datum = None # případně continue, pokud chceš řádek zahodit
|
||||||
|
|
||||||
|
# --- OBJEM ---
|
||||||
|
objem_str = (row.get("Objem") or "").replace(" ", "").replace(",", ".")
|
||||||
|
try:
|
||||||
|
objem = float(objem_str)
|
||||||
|
except ValueError:
|
||||||
|
objem = None
|
||||||
|
|
||||||
|
# --- normalizace textů ---
|
||||||
|
data = {
|
||||||
|
"datum": datum,
|
||||||
|
"objem": objem,
|
||||||
|
"mena": clean(row.get("Měna")),
|
||||||
|
"cislo_uctu": clean(row.get("Číslo účtu")),
|
||||||
|
"protiucet": clean(row.get("Protiúčet")),
|
||||||
|
"kod_banky": clean(row.get("Kód banky")),
|
||||||
|
"ks": clean(row.get("KS")),
|
||||||
|
"vs": clean(row.get("VS")),
|
||||||
|
"ss": clean(row.get("SS")),
|
||||||
|
"zprava": clean(row.get("Zpráva pro příjemce")),
|
||||||
|
"poznamka": clean(row.get("Poznámka")),
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- fingerprint pro ladění duplicit ---
|
||||||
|
data["uniq_fp"] = build_fingerprint(data)
|
||||||
|
|
||||||
|
# --- INSERT (záměrně bez IGNORE, ať duplicitní řádky opravdu uvidíme) ---
|
||||||
|
placeholders = ", ".join(["%s"] * len(data))
|
||||||
|
sql = f"INSERT INTO `{TABLE_NAME}` ({', '.join(data.keys())}) VALUES ({placeholders})"
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(sql, list(data.values()))
|
||||||
|
inserted += 1
|
||||||
|
|
||||||
|
print(f"✅ Import hotový: vloženo {inserted} řádků.")
|
||||||
|
|
||||||
|
# ----- rychlý report duplicit podle fingerprintu -----
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT uniq_fp, COUNT(*) AS c
|
||||||
|
FROM `{TABLE_NAME}`
|
||||||
|
GROUP BY uniq_fp
|
||||||
|
HAVING c > 1
|
||||||
|
ORDER BY c DESC
|
||||||
|
LIMIT 10;
|
||||||
|
""")
|
||||||
|
dups = cur.fetchall()
|
||||||
|
|
||||||
|
if dups:
|
||||||
|
print("\n⚠️ TOP 10 duplicitních fingerprintů (uniq_fp, count):")
|
||||||
|
for r in dups:
|
||||||
|
print(f" {r['uniq_fp']} -> {r['c']}")
|
||||||
|
print("\n💡 Tip: SELECT * FROM `transactions` WHERE uniq_fp = '...';")
|
||||||
|
else:
|
||||||
|
print("✅ Žádné duplicity podle uniq_fp nenalezeny.")
|
||||||
|
|
||||||
|
# ======== MAIN ========
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if not CSV_PATH.exists():
|
||||||
|
raise SystemExit(f"❌ Soubor {CSV_PATH} nenalezen.")
|
||||||
|
import_fio_csv()
|
||||||
47
40 fio 02 diagnostika.py
Normal file
47
40 fio 02 diagnostika.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Diagnostický test: načti Fio CSV a ověř parsování datumu.
|
||||||
|
Nenačítá se do MySQL – pouze vypíše výsledek.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# ✅ Tvoje cesta k souboru
|
||||||
|
CSV_PATH = Path(r"u:\Dropbox\!!!Days\Downloads Z230\Vyhledane pohyby (1).csv")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_czech_date(s: str):
|
||||||
|
"""Očistí řetězec a zkusí dd.mm.yyyy."""
|
||||||
|
if not s:
|
||||||
|
return None
|
||||||
|
s = s.strip().replace("\u00A0", "").replace("\ufeff", "")
|
||||||
|
try:
|
||||||
|
return datetime.strptime(s, "%d.%m.%Y").date()
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(CSV_PATH, "r", encoding="utf-8-sig", newline="") as f:
|
||||||
|
reader = csv.DictReader(f, delimiter=";", quotechar='"')
|
||||||
|
rows = list(reader)
|
||||||
|
|
||||||
|
print(f"Načteno {len(rows)} řádků.\n")
|
||||||
|
print("Ukázka prvních 10 řádků s hodnotou Datum:\n")
|
||||||
|
|
||||||
|
for i, row in enumerate(rows[:10], start=1):
|
||||||
|
raw = row.get("Datum")
|
||||||
|
parsed = parse_czech_date(raw)
|
||||||
|
print(f"{i:02d}. raw={repr(raw)} -> parsed={parsed}")
|
||||||
|
|
||||||
|
input("\n🔸 Stiskni Enter pro pokračování nebo ukončení... ")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if not CSV_PATH.exists():
|
||||||
|
raise SystemExit(f"❌ Soubor {CSV_PATH} nenalezen.")
|
||||||
|
main()
|
||||||
45
40 fio struktura gpc.txt
Normal file
45
40 fio struktura gpc.txt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
Struktura GPC formátu (pro elektronické výpisy)
|
||||||
|
Výstupní soubor obsahuje záznamy "Data - výpis v Kč", "Data - obratová položka", které mají pevnou délku
|
||||||
|
130 znaků. Mezi jednotlivými údaji v záznamu není žádný oddělovač. Do pevné délky jsou údaje doplňovány
|
||||||
|
zleva příslušným počtem znaků nula.
|
||||||
|
Struktura záznamu "Data - výpis v Kč" :
|
||||||
|
byty Obsah
|
||||||
|
1 - 3 "074" = označení typu záznamu "Data - výpis v Kč"
|
||||||
|
4 - 19 přidělené č. účtu s vodícími nulami
|
||||||
|
20 - 39 20 alfanumerických znaků zkráceného názvu účtu, doplněných případně mezerami zprava
|
||||||
|
40 - 45 datum starého zůstatku ve formátu DDMMRR
|
||||||
|
46 - 59 starý zůstatek v haléřích 14 numerických znaků s vodícími nulami
|
||||||
|
60 znaménko starého zůstatku, 1 znak "+" či "-"
|
||||||
|
61 - 74 nový zůstatek v haléřích 14 numerických znaků s vodícími nulami
|
||||||
|
75 znaménko nového zůstatku, 1 znak "+" či "-"
|
||||||
|
76 - 89 obraty debet (MD) v haléřích 14 numerických znaků s vodícími nulami
|
||||||
|
90 znaménko obratů debet (MD), 1 znak "0" či "-"
|
||||||
|
91 -104obraty kredit (D) v haléřích 14 numerických znaků s vodícími nulami
|
||||||
|
105 znaménko obratů kredit (D), 1 znak "0" či "-"
|
||||||
|
106-108 pořadové číslo výpisu
|
||||||
|
109-114 datum účtování ve formátu DDMMRR
|
||||||
|
115-128 (vyplněno 14 znaky mezera z důvodu sjednocení délky záznamů)
|
||||||
|
129-130 ukončovací znaky CR a LF
|
||||||
|
Struktura záznamu "Data - obratová položka v Kč" :
|
||||||
|
byty obsah
|
||||||
|
1 - 3 "075" = označení typu záznamu "Data - obratová položka"
|
||||||
|
4 - 19 přidělené číslo účtu 16 numerických znaků s vodícími nulami
|
||||||
|
20 – 35číslo účtu 16 numerických znaků s vodícími nulami (případně v pořadí předčíslí + číslo účtu)
|
||||||
|
36 – 48číslo dokladu 13 numerických znaků
|
||||||
|
49 – 60částka v haléřích 12 numerických znaků s vodícími nulami
|
||||||
|
61 kód účtování vztažený k číslu účtu:
|
||||||
|
1 = položka debet
|
||||||
|
2 = položka kredit
|
||||||
|
4 = storno položky debet
|
||||||
|
5 = storno položky kredit
|
||||||
|
62 – 71variabilní symbol 10 numerických znaků s vodícími nulami
|
||||||
|
72 – 81konstantní symbol 10 numerických znaků s vodícími nulami ve tvaru BBBBKSYM, kde:
|
||||||
|
BBBB = kód banky,
|
||||||
|
KSYM = konstantní symbol
|
||||||
|
82 – 91specifický symbol 10 numerických znaků s vodícími nulami
|
||||||
|
92 – 97"000000" = valuta
|
||||||
|
98 –117 20 alfanumerických znaků zkráceného názvu klienta, doplněno případně mezerami zprava
|
||||||
|
118 "0"
|
||||||
|
119-122 "0203" = kód měny pro Kč
|
||||||
|
123-128 datum splatnosti ve formátu DDMMRR
|
||||||
|
129-130 ukončovací znaky CR a LF
|
||||||
Reference in New Issue
Block a user