瀏覽代碼

Datev-Export

- mit automatischem Export über die zwei letzten Jahre
- sha-Vergleich
- TypeHints
gc-server3 10 月之前
父節點
當前提交
bcaa63862c

文件差異過大導致無法顯示
+ 1 - 0
datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240514_112734.csv


文件差異過大導致無法顯示
+ 1 - 0
datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240515_104021.csv


+ 6 - 0
datev/export_extf.bat

@@ -0,0 +1,6 @@
+@echo off
+set PYTHON="C:\GlobalCube\Tasks\python"
+
+%PYTHON%\python.exe export_extf.py
+pause
+

+ 73 - 20
datev/export_extf.py

@@ -1,6 +1,8 @@
 from datetime import datetime
 import calendar
 import csv
+import hashlib
+from typing import Any, Generator, Literal
 import pyodbc
 from pathlib import Path
 
@@ -9,29 +11,37 @@ DSN = "dsn=GC_OPTIMA_64;uid=gaps;pwd=Gcbs12ma"
 
 
 class DatevConfig:
-    data_path: str = "datev/data"
-    export_path: str = "datev/export"
-    translation_file: str = "datev/data/uebersetzungstabelle.csv"
+    base_dir: str = str(Path(__file__).resolve().parent)
+    data_path: str = base_dir + "/data"
+    export_path: str = base_dir + "/export"
+    translation_file: str = data_path + "/uebersetzungstabelle.csv"
     csv_date: datetime = datetime.now()  # datetime(2023, 11, 20, 19, 2, 28, 714000)
-    geschaeftsjahr_beginn: datetime = datetime(2024, 1, 1)
+    geschaeftsjahr_monat: int = 1
     periode: str = "202301"
     berater: int = 30612
     mandant: int = 10139
     konto_laenge: int = 5
 
     @property
-    def datum_von(self):
+    def datum_von(self) -> datetime:
         return datetime(int(self.periode[:4]), int(self.periode[4:]), 1)
 
     @property
-    def datum_bis(self):
+    def datum_bis(self) -> datetime:
         year = int(self.periode[:4])
         month = int(self.periode[4:])
         end_of_month = calendar.monthrange(year, month)[1]
         return datetime(year, month, end_of_month)
 
     @property
-    def header2(self):
+    def geschaeftsjahr_beginn(self) -> datetime:
+        year = int(self.periode[:4])
+        if self.geschaeftsjahr_monat > datetime.now().month:
+            year -= 1
+        return datetime(year, self.geschaeftsjahr_monat, 1)
+
+    @property
+    def header2(self) -> str:
         res = [
             "Umsatz (ohne Soll/Haben-Kz)",
             "Soll/Haben-Kennzeichen",
@@ -156,18 +166,18 @@ class DatevConfig:
         '{0};"{1}";"{2}";;;"";"{9}";"{4}";"";{5};"{6}";"";;"{7}";;"";;;;"";"";'
         + '"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"{10}";"";;"";;"";;;;;;"";"";"";"";"";"";"";"";"";"";"";"";"";'
         + '"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";;;;"";;;;"";"";;"";;'
-        + ';;"";"";;"";;"";;"";"";;"";;{8};;'
+        + ';;"";"";;"";;"";;"";"";;"";;0;;'
     )
     # '592.80;H;EUR;"15800";90900;0101;6288;Opel Bank VoST 12/22  Lagerwag;1'
 
     @property
-    def export_file(self):
+    def export_file(self) -> str:
         timestamp = self.csv_date.strftime("%Y%m%d_%H%M%S")
         period = self.datum_von.strftime("%Y%m")
         return f"{self.export_path}/EXTF_Buchungsstapel_30612_10139_{period}_{timestamp}.csv"
 
     @property
-    def header(self):
+    def header(self) -> str:
         datev_header = {
             "Datev-Format-KZ": "EXTF",
             "Versionsnummer": 510,
@@ -208,7 +218,7 @@ class DatevConfig:
         return template.format(**datev_header)
 
 
-def get_translation(cfg: DatevConfig):
+def get_translation(cfg: DatevConfig) -> dict[str, str]:
     translation = {}
     with Path(cfg.translation_file).open("r", encoding="latin-1") as frh:
         for line in csv.reader(frh, delimiter=";"):
@@ -218,7 +228,7 @@ def get_translation(cfg: DatevConfig):
     return translation
 
 
-def from_database(period):
+def from_database(period) -> Generator[list[str], Any, None]:
     with pyodbc.connect(DSN) as conn:
         cursor = conn.cursor()
         query = (
@@ -230,15 +240,15 @@ def from_database(period):
             yield list(map(str, row[:9]))
 
 
-def from_csv(import_file):
+def from_csv(import_file) -> Generator[list[str], Any, None]:
     with import_file.open("r", encoding="latin-1") as frh:
         csv_reader = csv.reader(frh, delimiter=";")
         next(csv_reader)  # ignore header
         for row in csv_reader:
-            yield row[:9]
+            yield row
 
 
-def export_extf(period, import_method="csv"):
+def export_extf(period: str, import_method: Literal["csv", "db"] = "csv") -> None:
     cfg = DatevConfig()
     cfg.periode = period
     translation = get_translation(cfg)
@@ -262,14 +272,57 @@ def export_extf(period, import_method="csv"):
             if row[9] == row[3]:
                 missing.append(row[3])
             fwh.write(cfg.row_template.format(*row) + "\r\n")
-    print(set(missing))
+    # print(set(missing))
+
+
+def export_all_periods() -> None:
+    dt = datetime.now()
+    prev = str(dt.year - 1)
+    periods = [f"{prev}{x:02}" for x in range(1, 13)] + [f"{dt.year}{x:02}" for x in range(1, dt.month + 1)]
+
+    for year, month in periods:
+        period = f"{year}{month}"
+        export_extf(period, "db")
+
+
+def extf_files_equal_content(file1, file2):
+    with open(file1, "r", encoding="latin-1") as frh1:
+        frh1.readline()  # ignore header
+        data1 = frh1.read()
+
+    with open(file2, "r", encoding="latin-1") as frh2:
+        frh2.readline()  # ignore header
+        data2 = frh2.read()
 
+    print(calculate_sha256(data1))
+    print(calculate_sha256(data2))
 
-def export_all_periods():
-    for period in range(202301, 202313):
-        export_extf(str(period), "db")
+    return calculate_sha256(data1) == calculate_sha256(data2)
+
+
+def calculate_sha256(data) -> str:
+    return hashlib.sha256(data.encode()).hexdigest()
 
 
 if __name__ == "__main__":
     # export_all_periods()
-    export_extf("202401", "csv")
+    print(
+        extf_files_equal_content(
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240514_112734.csv",
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240514_112734.csv",
+        )
+    )
+    print(
+        extf_files_equal_content(
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240222_155629.csv",
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240514_112734.csv",
+        )
+    )
+    print(
+        extf_files_equal_content(
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240514_112734.csv",
+            "datev/export/EXTF_Buchungsstapel_30612_10139_202312_20240515_104021.csv",
+        )
+    )
+
+    # os.makedirs(Path(filename).parent.joinpath("info"), exist_ok=True)

部分文件因文件數量過多而無法顯示