gcstruct.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. import csv
  2. import json
  3. import re
  4. import xml.etree.ElementTree as ET
  5. from functools import reduce
  6. from pathlib import Path
  7. import chevron
  8. import numpy as np
  9. import pandas as pd
  10. # from shutil import copyfile
  11. from bs4 import BeautifulSoup
  12. def get_flat(node):
  13. result = [
  14. {
  15. "id": node["id"],
  16. "text": node["text"],
  17. "amount_text": node["amount_text"],
  18. "children": [x["id"] for x in node["children"]],
  19. "children2": [],
  20. "parents": node["parents"],
  21. "accounts": node["accounts"],
  22. "costcenter": "",
  23. "level": node["level"],
  24. "drilldown": node["level"] < 2, # (node['level'] != 2 and len(node['accounts']) == 0),
  25. "form": node["form"],
  26. "accountlevel": False,
  27. "absolute": True,
  28. "seasonal": True,
  29. "status": "0",
  30. "values": [],
  31. "values2": {},
  32. }
  33. ]
  34. for child in node["children"]:
  35. result += get_flat(child)
  36. return result
  37. def get_parents_list(p_list):
  38. id = ";".join(p_list) + ";" * (10 - len(p_list))
  39. if len(p_list) > 0:
  40. return [id] + get_parents_list(p_list[:-1])
  41. return [";" * 9]
  42. def structure_from_tree(node):
  43. result = []
  44. result.append(node["id"])
  45. for child in node["children"]:
  46. result.extend(structure_from_tree(child))
  47. return result
  48. def xml_from_tree(xml_node, tree_node):
  49. for child in tree_node["children"]:
  50. element = ET.SubElement(xml_node, "Ebene")
  51. element.set("Name", child["text"])
  52. xml_from_tree(element, child)
  53. def split_it(text, index):
  54. try:
  55. return re.findall(r"([^;]+) - ([^;]*);;", text)[0][index]
  56. except Exception:
  57. return ""
  58. def last_layer(text):
  59. try:
  60. return re.findall(r"([^;]+);;", text)[0]
  61. except Exception:
  62. return ""
  63. def get_default_cols(i):
  64. return ["Ebene" + str(i) for i in range(i * 10 + 1, (i + 1) * 10 + 1)]
  65. def get_structure_exports(s):
  66. result = {
  67. "files": {},
  68. "format": {
  69. "KontoFormat": "{0} - {1}",
  70. "HerstellerkontoFormat": "{{Herstellerkonto_Nr}}",
  71. "HerstellerBezeichnungFormat": "{{Herstellerkonto_Bez}}",
  72. "NeueHerstellerkontenAnlegen": False,
  73. },
  74. }
  75. export_files = [
  76. "ExportStk",
  77. "ExportStrukturenStk",
  78. "ExportAdjazenz",
  79. "ExportUebersetzung",
  80. "ExportUebersetzungStk",
  81. "ExportHerstellerKontenrahmen",
  82. ]
  83. export_format = [
  84. "KontoFormat",
  85. "HerstellerkontoFormat",
  86. "HerstellerBezeichnungFormat",
  87. "NeueHerstellerkontenAnlegen",
  88. ]
  89. for e in export_files:
  90. if s.find(e) is not None and s.find(e).text is not None and s.find(e).text[-4:] == ".csv":
  91. result["files"][e] = s.find(e).text
  92. for e in export_format:
  93. if s.find(e) is not None and s.find(e).text != "":
  94. result["format"][e] = s.find(e).text
  95. result["format"]["NeueHerstellerkontenAnlegen"] = result["format"]["NeueHerstellerkontenAnlegen"] == "true"
  96. return result
  97. class GCStruct:
  98. config = {
  99. "path": "c:/projekte/python/gcstruct",
  100. "path2": "c:/projekte/python/gcstruct",
  101. "file": "c:/projekte/python/gcstruct/config/config.xml",
  102. "output": "gcstruct.json",
  103. "default": [],
  104. "special": {},
  105. "special2": {
  106. "Planner": ["Kostenstelle", "Ebene1", "Ebene2"],
  107. "Test": ["Ebene1", "Ebene2"],
  108. },
  109. "columns": [
  110. "Konto_Nr",
  111. "Konto_Bezeichnung",
  112. "Konto_Art",
  113. "Konto_KST",
  114. "Konto_STK",
  115. "Konto_1",
  116. "Konto_2",
  117. "Konto_3",
  118. "Konto_4",
  119. "Konto_5",
  120. ],
  121. "struct": {},
  122. "export": {},
  123. }
  124. json_result = {
  125. "accounts": {},
  126. "tree": {},
  127. "flat": {},
  128. "struct_export": {},
  129. "skr51_vars": {},
  130. }
  131. structure_ids = []
  132. translate = {
  133. "Konto_Nr": "SKR51",
  134. "Kostenstelle": "KST",
  135. "Absatzkanal": "ABS",
  136. "Kostenträger": "KTR",
  137. "Marke": "MAR",
  138. "Standort": "STA",
  139. "Marke_HBV": "MAR",
  140. "Standort_HBV": "BMC",
  141. }
  142. def __init__(self, struct_dir, export_dir=None):
  143. self.config["path"] = struct_dir
  144. self.config["path2"] = struct_dir + "/export" if export_dir is None else export_dir
  145. self.config["file"] = f"{self.config['path']}/config/gcstruct.xml"
  146. if not Path(self.config["file"]).exists():
  147. self.config["file"] = f"{self.config['path']}/config/config.xml"
  148. cfg = ET.parse(self.config["file"])
  149. self.config["default"] = [
  150. s.find("Name").text for s in cfg.getroot().find("Strukturdefinitionen").findall("Struktur")
  151. ]
  152. self.config["export"] = dict(
  153. [
  154. (s.find("Name").text, get_structure_exports(s))
  155. for s in cfg.getroot().find("Strukturdefinitionen").findall("Struktur")
  156. ]
  157. )
  158. struct = dict([(x, get_default_cols(i)) for (i, x) in enumerate(self.config["default"])])
  159. struct.update(self.config["special"])
  160. self.config["struct"] = struct
  161. # print(self.config['struct'])
  162. def export_header(self, filetype):
  163. return {
  164. "ExportStk": [],
  165. "ExportStrukturenStk": [],
  166. "ExportAdjazenz": [],
  167. "ExportUebersetzung": [
  168. "Konto_Nr_Hersteller",
  169. "Konto_Nr_Split",
  170. "Konto_Nr_Haendler",
  171. "Info",
  172. ],
  173. "ExportUebersetzungStk": [
  174. "Konto_Nr_Hersteller",
  175. "Konto_Nr_Split",
  176. "Konto_Nr_Haendler",
  177. "Info",
  178. ],
  179. "ExportHerstellerKontenrahmen": [
  180. "Konto_Nr",
  181. "Konto_Bezeichnung",
  182. "Case",
  183. "Info",
  184. ],
  185. }.get(filetype, [])
  186. def accounts_from_csv(self, struct):
  187. max_rows = (len(self.config["default"]) + 1) * 10
  188. with open(
  189. f"{self.config['path']}/Kontenrahmen/Kontenrahmen.csv",
  190. "r",
  191. encoding="latin-1",
  192. ) as f:
  193. csv_reader = csv.reader(f, delimiter=";")
  194. imported_csv = [row[:max_rows] for row in csv_reader]
  195. df = pd.DataFrame.from_records(np.array(imported_csv[1:], dtype="object"), columns=imported_csv[0]).fillna(
  196. value=""
  197. )
  198. df = df.rename(columns={"Kostenstelle": "Konto_KST", "STK": "Konto_STK"})
  199. for i, (s, cols) in enumerate(struct.items()):
  200. df[s] = reduce(lambda x, y: x + ";" + df[y], cols, "")
  201. df[s] = df[s].apply(lambda x: x[1:])
  202. df["LetzteEbene" + str(i + 1)] = df[s].apply(lambda x: last_layer(x))
  203. df["LetzteEbene" + str(i + 1) + "_Nr"] = df[s].apply(lambda x: split_it(x, 0))
  204. df["LetzteEbene" + str(i + 1) + "_Bez"] = df[s].apply(lambda x: split_it(x, 1))
  205. df["Herstellerkonto_Nr"] = df["LetzteEbene1_Nr"]
  206. df["Herstellerkonto_Bez"] = df["LetzteEbene1_Bez"]
  207. return df
  208. def tree_from_xml(self, struct, df):
  209. result = {}
  210. for s, cols in struct.items():
  211. try:
  212. tree = ET.parse(f"{self.config['path']}/Xml/{s}.xml")
  213. result[s] = self.get_tree_root(tree.getroot(), s)
  214. except FileNotFoundError:
  215. print("XML-Datei fehlt")
  216. used_entries = [x.split(";")[1:] for x in set(df[s].to_numpy())]
  217. print(used_entries)
  218. root = ET.Element("Ebene")
  219. root.set("Name", s)
  220. result[s] = self.get_tree_root(root, s)
  221. # self.json_result["tree"][s] = get_tree_from_accounts(cols, [])
  222. return result
  223. def get_structure_and_tree(self):
  224. df = self.accounts_from_csv(self.config["struct"])
  225. self.json_result["accounts"] = df.to_dict("records")
  226. self.structure_ids = df.melt(
  227. id_vars=["Konto_Nr"],
  228. value_vars=self.config["struct"].keys(),
  229. var_name="Struktur",
  230. value_name="id",
  231. ).groupby(by=["Struktur", "id"])
  232. self.json_result["tree"] = self.tree_from_xml(self.config["struct"], df)
  233. for s, cols in self.config["struct"].items():
  234. self.json_result["flat"][s] = get_flat(self.json_result["tree"][s])
  235. for s, entries in self.json_result["flat"].items():
  236. cols = self.config["struct"][s]
  237. df_temp = pd.DataFrame([x["id"].split(";") for x in entries], columns=cols)
  238. self.json_result["struct_export"][s] = df_temp.to_dict(orient="records")
  239. # {'accounts': {}, 'tree': {}, 'flat': {}, 'struct_export': {}, 'skr51_vars': {}}
  240. return self.json_result
  241. def export_structure_and_tree(self):
  242. json.dump(
  243. self.json_result,
  244. open(f"{self.config['path2']}/{self.config['output']}", "w"),
  245. indent=2,
  246. )
  247. def get_accounts(self, structure, id):
  248. return [x["Konto_Nr"] for x in self.json_result["accounts"] if x[structure] == id]
  249. # return []
  250. # res = self.structure_ids.groups.get((structure, id))
  251. # if res is None:
  252. # return []
  253. # return res.values
  254. def export(self):
  255. for s in self.config["export"].keys():
  256. if len(self.config["export"][s]["files"]) == 0:
  257. continue
  258. struct_info = {e["id"]: e for e in self.json_result["flat"][s]}
  259. for filetype, filename in self.config["export"][s]["files"].items():
  260. with open(
  261. self.config["path2"] + "/" + filename,
  262. "w",
  263. encoding="latin-1",
  264. errors="ignore",
  265. ) as fwh:
  266. fwh.write(";".join(self.export_header(filetype)) + "\n")
  267. unique_accounts = []
  268. for a in self.json_result["accounts"]:
  269. if a["Herstellerkonto_Nr"] == "":
  270. continue
  271. account = chevron.render(
  272. self.config["export"]["SKR51"]["format"]["HerstellerkontoFormat"],
  273. a,
  274. )
  275. amount_text = struct_info.get(a[s], {}).get("amount_text", "")
  276. if amount_text == "" or " - " not in amount_text:
  277. amount_text += " - "
  278. account_amount_nr, account_amount_text = amount_text.split(" - ")
  279. a2 = a.copy()
  280. a2["Herstellerkonto_Nr"] = account_amount_nr
  281. a2["Herstellerkonto_Bez"] = account_amount_text
  282. account2 = chevron.render(
  283. self.config["export"]["SKR51"]["format"]["HerstellerkontoFormat"],
  284. a2,
  285. )
  286. if filetype == "ExportUebersetzungStk" and a["Konto_STK"] != "1":
  287. continue
  288. if filetype == "ExportHerstellerKontenrahmen":
  289. if account not in unique_accounts:
  290. unique_accounts.append(account)
  291. account_text = chevron.render(
  292. self.config["export"]["SKR51"]["format"]["HerstellerBezeichnungFormat"],
  293. a,
  294. )
  295. fwh.write(account + ";" + account_text + ";2;" + a["Herstellerkonto_Bez"] + "\n")
  296. if account_amount_nr != "" and account2 not in unique_accounts:
  297. unique_accounts.append(account2)
  298. account_text = chevron.render(
  299. self.config["export"]["SKR51"]["format"]["HerstellerBezeichnungFormat"],
  300. a2,
  301. )
  302. fwh.write(account2 + ";" + account_text + ";2;" + a["Herstellerkonto_Bez"] + "\n")
  303. elif filetype == "ExportUebersetzungStk":
  304. fwh.write(account2 + ";" + account2 + ";" + a["Konto_Nr"] + ";" + "\n")
  305. else:
  306. fwh.write(account + ";" + account + ";" + a["Konto_Nr"] + ";" + "\n")
  307. def get_tree(self, node, parents, structure):
  308. result = []
  309. for child in node:
  310. p = get_parents_list(parents)
  311. parents.append(child.attrib["Name"])
  312. id = ";".join(parents) + ";" * (10 - len(parents))
  313. result.append(
  314. {
  315. "id": id,
  316. "text": child.attrib["Name"],
  317. "children": self.get_tree(child, parents, structure),
  318. "parents": p,
  319. "accounts": self.get_accounts(structure, id),
  320. "level": len(parents),
  321. "form": child.attrib.get("Split", ""),
  322. "amount_text": child.attrib.get("NameStk", ""),
  323. }
  324. )
  325. parents.pop()
  326. return result
  327. def get_tree_root(self, node, structure):
  328. id = ";" * 9
  329. return {
  330. "id": id,
  331. "text": node.attrib["Name"],
  332. "children": self.get_tree(node, [], structure),
  333. "parents": [],
  334. "accounts": [],
  335. "level": 0,
  336. "form": "",
  337. "amount_text": "",
  338. }
  339. def post_structure_and_tree(self):
  340. json_post = json.load(open(f"{self.config['path']}/{self.config['output']}", "r"))
  341. # Kontenrahmen.csv
  342. ebenen = ["Ebene" + str(i) for i in range(1, len(self.config["default"]) * 10 + 1)]
  343. header = ";".join(self.config["columns"] + ebenen)
  344. cols = self.config["columns"] + self.config["default"]
  345. with open(
  346. self.config["path"] + "/Kontenrahmen/Kontenrahmen_out.csv",
  347. "w",
  348. encoding="latin-1",
  349. ) as f:
  350. f.write(header + "\n")
  351. for row in json_post["Kontenrahmen"]:
  352. f.write(";".join([row[e] for e in cols]) + "\n")
  353. # print(header)
  354. # xml und evtl. Struktur.csv
  355. for i, s in enumerate(self.config["default"]):
  356. with open(
  357. f"{self.config['path']}/Strukturen/Kontenrahmen.csv/{s}_out.csv",
  358. "w",
  359. encoding="latin-1",
  360. ) as f:
  361. f.write(";".join(["Ebene" + str(i * 10 + j) for j in range(1, 11)]) + "\n")
  362. rows = structure_from_tree({"id": ";" * 9, "children": json_post[s]})
  363. f.write("\n".join(rows))
  364. # with open(self.config['path'] + "/Strukturen/Kontenrahmen.csv/" + structure + "_2.csv", "w", encoding="latin-1") as f:
  365. root = ET.Element("Ebene")
  366. root.set("Name", s)
  367. xml_from_tree(root, {"id": ";" * 9, "children": json_post[s]})
  368. with open(f"{self.config['path']}/Xml/{s}_out.xml", "w", encoding="utf-8") as f:
  369. f.write(BeautifulSoup(ET.tostring(root), "xml").prettify())
  370. def skr51_translate(self, accounts_combined_files):
  371. # self.get_structure_and_tree()
  372. df = self.accounts_from_csv(self.config["struct"])
  373. df["KRM_Nr"] = df["Konto_Nr"].apply(lambda x: x.split("_")[-1])
  374. # structure_index = {}
  375. # for i, s in enumerate(self.config["struct"].keys()):
  376. # structure_index[s] = dict((e["id"], j) for j, e in enumerate(self.json_result["flat"][s]))
  377. df_translate = {}
  378. for i, (t_from, t_to) in enumerate(self.translate.items()):
  379. last = "LetzteEbene" + str(i + 1)
  380. from_label = [
  381. "Konto_Nr",
  382. "Konto_Bezeichnung",
  383. last,
  384. last + "_Nr",
  385. last + "_Bez",
  386. "Ebene" + str(i * 10 + 1),
  387. "Ebene" + str(i * 10 + 2),
  388. "KRM_Nr",
  389. ]
  390. to_label = [
  391. t_to,
  392. t_to + "_Bez_Händler",
  393. t_to + "_Ebene",
  394. t_to + "_Nr",
  395. t_to + "_Bez",
  396. t_to + "_Ebene1",
  397. t_to + "_Ebene2",
  398. t_to + "_Nr_Händler",
  399. ]
  400. df_translate[t_from] = df[df[last + "_Nr"] != ""][from_label].rename(
  401. columns=dict(zip(from_label, to_label))
  402. )
  403. # for (t_from, t_to), (s, idx) in zip(self.translate.items(), structure_index.items()):
  404. # df_translate[t_from][t_to + "_Sortierung"] = df_translate[t_from]
  405. df_t4 = df_translate["Konto_Nr"].copy()
  406. df_t4 = df_t4[df_t4["SKR51_Nr"].str.match(r"^[01]")]
  407. df_t5 = df_t4.copy()
  408. df_t4["SKR51_Nr"] = df_t4["SKR51_Nr"] + "_A"
  409. df_t4["SKR51"] = df_t4["SKR51"] + "_A"
  410. df_t5["SKR51_Nr"] = df_t5["SKR51_Nr"] + "_P"
  411. df_t5["SKR51"] = df_t5["SKR51"] + "_P"
  412. df_translate["Konto_Nr"] = pd.concat([df_translate["Konto_Nr"], df_t4, df_t5])
  413. # print(df_translate[t_to].head())
  414. df2 = []
  415. for ac_file in accounts_combined_files:
  416. df_temp = pd.read_csv(
  417. ac_file,
  418. decimal=",",
  419. sep=";",
  420. encoding="latin-1",
  421. converters={i: str for i in range(0, 200)},
  422. )
  423. if "Kostenträger_Marke" not in df_temp.columns:
  424. df_temp["Kostenträger_Marke"] = df_temp["Marke"]
  425. df2.append(df_temp)
  426. df_source = pd.concat(df2)
  427. df3 = df_source.copy()
  428. df3["Konto_Nr"] = df3["Konto_Nr"] + "_STK"
  429. df4 = df_source.copy()
  430. df4 = df4[df4["Konto_Nr"].str.match(r"^[01]")]
  431. df5 = df4.copy()
  432. df4["Konto_Nr"] = df4["Konto_Nr"] + "_A"
  433. df5["Konto_Nr"] = df5["Konto_Nr"] + "_P"
  434. df_source = pd.concat([df_source, df3, df4, df5])
  435. for t_from, t_to in self.translate.items():
  436. if t_to == "SKR51":
  437. df_source["SKR51"] = df_source["Konto_Nr"]
  438. elif t_from in ["Marke_HBV"]:
  439. df_source["Marke_HBV"] = df_source["Marke"]
  440. elif t_from in ["Standort_HBV"]:
  441. df_source["Standort_HBV"] = df_source["Standort"] + "_" + df_source["Marke"]
  442. df_source["BMC"] = "BMC_" + df_source["Standort_HBV"]
  443. elif t_to == "KTR":
  444. df_source["KTR"] = np.where(
  445. df_source["Kostenträger_Quelle"] == "TZ",
  446. "KTR_TZ_" + df_source["Kostenträger"],
  447. "KTR_00",
  448. )
  449. df_source["KTR"] = np.where(
  450. df_source["Kostenträger_Quelle"].isin(["NW", "SC"]),
  451. "KTR_"
  452. + df_source["Kostenträger_Quelle"]
  453. + "_"
  454. + df_source["Kostenträger_Marke"]
  455. + "_"
  456. + df_source["Kostenträger"],
  457. df_source["KTR"],
  458. )
  459. else:
  460. df_source[t_to] = t_to + "_" + df_source[t_from]
  461. df_source = df_source.merge(df_translate[t_from], how="left", on=[t_to], suffixes=(None, "_" + t_to))
  462. df_source[t_to + "_Nr"] = np.where(
  463. df_source[t_to + "_Nr"].isna(),
  464. df_source[t_from],
  465. df_source[t_to + "_Nr"],
  466. )
  467. df_source["Konto_Nr_SKR51"] = (
  468. df_source["MAR_Nr"]
  469. + "-"
  470. + df_source["STA_Nr"]
  471. + "-"
  472. + df_source["SKR51_Nr"]
  473. + "-"
  474. + df_source["KST_Nr"]
  475. + "-"
  476. + df_source["ABS_Nr"]
  477. + "-"
  478. + df_source["KTR_Nr"]
  479. )
  480. df_source["Konto_Nr_Händler"] = (
  481. df_source["Marke"]
  482. + "-"
  483. + df_source["Standort"]
  484. + "-"
  485. + df_source["Konto_Nr"]
  486. + "-"
  487. + df_source["Kostenstelle"]
  488. + "-"
  489. + df_source["Absatzkanal"]
  490. + "-"
  491. + df_source["Kostenträger"]
  492. )
  493. df_source["Konto_Nr_Händler_mit_KST"] = df_source["Konto_Nr"] + "_" + df_source["Kostenstelle"]
  494. # df_source.to_csv(f"{self.config['path2']}/SKR51_Uebersetzung.csv", sep=';', encoding='latin-1', index=False)
  495. df_source["MAR_Nr_MAR"] = np.where(df_source["MAR_Nr_MAR"].isna(), "0000", df_source["MAR_Nr_MAR"])
  496. df_source["SKR51_Sortierung"] = df_source["SKR51_Nr"]
  497. df_source["KST_Sortierung"] = df_source["KST_Nr"]
  498. df_source["ABS_Sortierung"] = df_source["ABS_Nr"]
  499. df_source["KTR_Sortierung"] = df_source["KTR_Nr"]
  500. df_source["MAR_Sortierung"] = df_source["MAR_Nr"]
  501. df_source["STA_Sortierung"] = df_source["STA_Nr"]
  502. df_source["MAR2_Sortierung"] = df_source["MAR_Nr_MAR"]
  503. df_source["BMC_Sortierung"] = df_source["BMC_Nr"]
  504. df_source["Kostenträger_Ebene"] = df_source["KTR_Ebene"]
  505. from_label = [
  506. "Konto_Nr_Händler",
  507. "Konto_Nr_SKR51",
  508. "MAR_Nr",
  509. "STA_Nr",
  510. "SKR51_Nr",
  511. "KST_Nr",
  512. "ABS_Nr",
  513. "KTR_Nr",
  514. "Kostenträger_Ebene",
  515. "MAR_Nr_MAR",
  516. "BMC_Nr",
  517. "Konto_Nr",
  518. "Konto_Nr_Händler_mit_KST",
  519. "SKR51_Bez_Händler",
  520. "SKR51_Ebene1",
  521. "SKR51_Ebene2",
  522. "SKR51_Sortierung",
  523. "KST_Ebene1",
  524. "KST_Ebene2",
  525. "KST_Ebene",
  526. "KST_Sortierung",
  527. "ABS_Ebene1",
  528. "ABS_Ebene2",
  529. "ABS_Ebene",
  530. "ABS_Sortierung",
  531. "KTR_Ebene1",
  532. "KTR_Ebene2",
  533. "KTR_Ebene",
  534. "KTR_Sortierung",
  535. "MAR_Ebene1",
  536. "MAR_Ebene2",
  537. "MAR_Ebene",
  538. "MAR_Sortierung",
  539. "STA_Ebene1",
  540. "STA_Ebene2",
  541. "STA_Ebene",
  542. "STA_Sortierung",
  543. "MAR_Ebene1_MAR",
  544. "MAR_Ebene2_MAR",
  545. "MAR_Ebene_MAR",
  546. "MAR2_Sortierung",
  547. "BMC_Ebene1",
  548. "BMC_Ebene2",
  549. "BMC_Ebene",
  550. "BMC_Sortierung",
  551. "KST_Nr_Händler",
  552. "KST_Bez_Händler",
  553. "ABS_Nr_Händler",
  554. "ABS_Bez_Händler",
  555. "KTR_Nr_Händler",
  556. "KTR_Bez_Händler",
  557. "MAR_Nr_Händler",
  558. "MAR_Bez_Händler",
  559. ]
  560. to_label = [
  561. "Konto_Nr_Händler",
  562. "Konto_Nr_SKR51",
  563. "Marke",
  564. "Standort",
  565. "Konto_Nr",
  566. "Kostenstelle",
  567. "Absatzkanal",
  568. "Kostenträger",
  569. "Kostenträger_Ebene",
  570. "Marke_HBV",
  571. "Standort_HBV",
  572. "Konto_Nr_Händler_kurz",
  573. "Konto_Nr_Händler_mit_KST",
  574. "Konto_Bezeichnung_Händler",
  575. "SKR51_Ebene1",
  576. "SKR51_Ebene2",
  577. "SKR51_Sortierung",
  578. "KST_Ebene1",
  579. "KST_Ebene2",
  580. "KST_Text",
  581. "KST_Sortierung",
  582. "ABS_Ebene1",
  583. "ABS_Ebene2",
  584. "ABS_Text",
  585. "ABS_Sortierung",
  586. "KTR_Ebene1",
  587. "KTR_Ebene2",
  588. "KTR_Text",
  589. "KTR_Sortierung",
  590. "MAR_Ebene1",
  591. "MAR_Ebene2",
  592. "MAR_Text",
  593. "MAR_Sortierung",
  594. "STA_Ebene1",
  595. "STA_Ebene2",
  596. "STA_Text",
  597. "STA_Sortierung",
  598. "MAR2_Ebene1",
  599. "MAR2_Ebene2",
  600. "MAR2_Text",
  601. "MAR2_Sortierung",
  602. "BMCode_Ebene1",
  603. "BMCode_Ebene2",
  604. "BMCode_Text",
  605. "BMCode_Sortierung",
  606. "KST_Nr_Händler",
  607. "KST_Bez_Händler",
  608. "ABS_Nr_Händler",
  609. "ABS_Bez_Händler",
  610. "KTR_Nr_Händler",
  611. "KTR_Bez_Händler",
  612. "MAR_Nr_Händler",
  613. "MAR_Bez_Händler",
  614. ]
  615. df_combined = df_source[from_label].rename(columns=dict(zip(from_label, to_label)))
  616. df_combined.to_csv(
  617. f"{self.config['path2']}/Kontenrahmen_uebersetzt.csv",
  618. sep=";",
  619. encoding="latin-1",
  620. index=False,
  621. )
  622. def skr51_translate2(self, accounts_combined_file):
  623. df = self.accounts_from_csv(self.config["struct"])
  624. df_list = []
  625. for i, s in enumerate(self.config["struct"].keys()):
  626. from_label = [
  627. "Konto_Nr",
  628. "Ebene" + str(i * 10 + 1),
  629. "Ebene" + str(i * 10 + 2),
  630. "Ebene" + str(i * 10 + 3),
  631. ]
  632. to_label = ["Konto_Nr", "key", "value", "value2"]
  633. df_temp = df[from_label].rename(columns=dict(zip(from_label, to_label)))
  634. df_temp["key"] = "{" + s + "/" + df_temp["key"] + "}"
  635. df_list.append(df_temp[df_temp["value"] != ""])
  636. df_translate = pd.concat(df_list)
  637. # df_translate.to_csv(f"{self.config['path2']}/SKR51_Variablen.csv", sep=';', encoding='latin-1', index=False)
  638. df_source = pd.read_csv(
  639. accounts_combined_file,
  640. decimal=",",
  641. sep=";",
  642. encoding="latin-1",
  643. converters={i: str for i in range(0, 200)},
  644. )
  645. df_source = df_source[df_source["Konto_Nr"].str.contains("_STK") == False]
  646. df_source["Konto_Nr_Gesamt"] = df_source["Konto_Nr"]
  647. df_source["Konto_Nr"] = np.where(
  648. df_source["Konto_Nr"].str.contains(r"^[4578]"),
  649. df_source["Konto_Nr"] + "_" + df_source["Kostenstelle"].str.slice(stop=1),
  650. df_source["Konto_Nr"],
  651. )
  652. df_source["Konto_Nr"] = np.where(
  653. df_source["Konto_Nr"].str.contains(r"^5\d+_4"),
  654. df_source["Konto_Nr"] + df_source["Kostenstelle"].str.slice(start=1, stop=2),
  655. df_source["Konto_Nr"],
  656. )
  657. df_source = df_source.merge(df, how="left", on=["Konto_Nr"])
  658. # rows = df_source.shape[0]
  659. df_source["value"] = ""
  660. cols = get_default_cols(0)
  661. for t_from, t_to in self.translate.items():
  662. if t_from in ["Marke_HBV", "Standort_HBV"]:
  663. continue
  664. if t_from == "Konto_Nr":
  665. df_source[t_to] = df_source[t_from]
  666. else:
  667. df_source[t_to] = t_to + "_" + df_source[t_from]
  668. for e in cols:
  669. df_source = df_source.merge(
  670. df_translate,
  671. how="left",
  672. left_on=[t_to, e],
  673. right_on=["Konto_Nr", "key"],
  674. suffixes=(None, "_" + t_to + "_" + e),
  675. )
  676. df_source[e] = np.where(
  677. df_source["value_" + t_to + "_" + e].notna(),
  678. df_source["value_" + t_to + "_" + e],
  679. df_source[e],
  680. )
  681. # if df_source.shape[0] > rows:
  682. # print(t_to + '_' + e + ': ' + str(df_source.shape[0]))
  683. # df_source.to_csv(f"{self.config['path2']}/SKR51_Variablen2.csv", sep=';', encoding='latin-1', index=False)
  684. # df_source[t_to + '_Nr'] = np.where(df_source[t_to + '_Nr'].isna(), df_source[t_from], df_source[t_to + '_Nr'])
  685. for e in cols:
  686. df_source[e] = np.where(
  687. df_source[e].str.startswith("{"),
  688. df_source[e].str.extract(r"\/(.*)}", expand=False) + " falsch",
  689. df_source[e],
  690. ) # df_source[e].str.extract(r'/(.*)}') +
  691. df_source[e] = np.where(df_source[e] == "[KTR]", df_source["Kostenträger_Ebene"], df_source[e])
  692. # df_all[df_all['Ebene1'] == ]
  693. # print(df_source.head())
  694. df_source["Konto_neu"] = (
  695. df_source["Marke"]
  696. + "-"
  697. + df_source["Standort"]
  698. + "-"
  699. + df_source["Konto_Nr"]
  700. + "-"
  701. + df_source["Kostenstelle"]
  702. + "-"
  703. + df_source["Absatzkanal"]
  704. + "-"
  705. + df_source["Kostenträger"]
  706. + " - "
  707. + df_source["Konto_Bezeichnung"]
  708. )
  709. df_source["Ebene1_empty"] = df_source["Ebene1"].isna() # , df_source['Ebene1'].map(lambda x: x == ''))
  710. df_source["Konto_neu"] = np.where(df_source["Ebene1_empty"], "keine Zuordnung", df_source["Konto_neu"])
  711. df_source["Ebene1"] = np.where(df_source["Ebene1_empty"], "keine Zuordnung", df_source["Ebene1"])
  712. df_source["Konto_Gruppe"] = df_source["Konto_Nr"] + " - " + df_source["Konto_Bezeichnung"]
  713. df_source["Konto_Gruppe"] = np.where(df_source["Ebene1_empty"], "keine Zuordnung", df_source["Konto_Gruppe"])
  714. df_source["Konto_Gesamt"] = df_source["Konto_Nr_Gesamt"] + " - " + df_source["Konto_Bezeichnung"]
  715. df_source["Konto_Händler"] = df_source["Konto_Nr_Händler_kurz"] + " - " + df_source["Konto_Bezeichnung_Händler"]
  716. df_source["Konto_mit_KST_Händler"] = (
  717. df_source["Konto_Nr_Händler_mit_KST"] + " - " + df_source["Konto_Bezeichnung_Händler"]
  718. )
  719. kto_amount = df_source["Ebene63"] == "mit STK"
  720. if kto_amount.sum() > 0:
  721. df_amount = df_source[kto_amount].reset_index()
  722. else:
  723. df_amount = df_source[df_source["Ebene1"] == "Umsatzerlöse"].reset_index()
  724. df_amount["Ebene1"] = "verkaufte Stückzahlen"
  725. df_amount["Ebene72"] = "verkaufte Stückzahlen"
  726. df_amount["Konto_neu"] = "STK " + df_amount["Konto_neu"]
  727. df_amount["Konto_Nr_Händler"] = df_amount["Konto_Nr_Händler"] + "_STK"
  728. df_amount["Konto_Gruppe"] = "STK " + df_amount["Konto_Gruppe"]
  729. df_amount["Konto_Gesamt"] = "STK " + df_amount["Konto_Gesamt"]
  730. df_amount["Konto_Händler"] = "STK " + df_amount["Konto_Händler"]
  731. df_amount["Konto_mit_KST_Händler"] = "STK " + df_amount["Konto_mit_KST_Händler"]
  732. df_source = pd.concat([df_source, df_amount])
  733. if "Ebene81" in df_source.columns:
  734. df_source["Ebene91"] = df_source["Ebene81"]
  735. df_source["Ebene92"] = df_source["Ebene82"]
  736. df_source["Ebene93"] = df_source["Ebene83"]
  737. df_source["Ebene94"] = df_source["Ebene84"]
  738. df_source["Ebene95"] = df_source["Ebene85"]
  739. df_source["Ebene96"] = df_source["Ebene86"]
  740. df_source["Ebene97"] = df_source["Ebene87"]
  741. df_source["Ebene98"] = df_source["Ebene88"]
  742. df_source["Ebene99"] = df_source["Ebene89"]
  743. df_source["Ebene100"] = df_source["Ebene90"]
  744. else:
  745. df_source["Ebene91"] = ""
  746. df_source["Ebene92"] = ""
  747. df_source["Ebene93"] = ""
  748. df_source["Ebene94"] = ""
  749. df_source["Ebene95"] = ""
  750. df_source["Ebene96"] = ""
  751. df_source["Ebene97"] = ""
  752. df_source["Ebene98"] = ""
  753. df_source["Ebene99"] = ""
  754. df_source["Ebene100"] = ""
  755. df_source["GuV"] = df_source["Ebene71"] == "GuV"
  756. df_source["Ebene81"] = np.where(df_source["GuV"], df_source["Ebene72"], "Bilanz")
  757. df_source["Ebene82"] = np.where(df_source["GuV"], df_source["Ebene73"], "")
  758. df_source["Ebene83"] = np.where(df_source["GuV"], df_source["Ebene74"], "")
  759. df_source["Ebene84"] = np.where(df_source["GuV"], df_source["Ebene75"], "")
  760. df_source["Ebene85"] = np.where(df_source["GuV"], df_source["Ebene76"], "")
  761. df_source["Ebene86"] = np.where(df_source["GuV"], df_source["Ebene77"], "")
  762. df_source["Ebene87"] = np.where(df_source["GuV"], df_source["Ebene78"], "")
  763. df_source["Ebene88"] = np.where(df_source["GuV"], df_source["Ebene79"], "")
  764. df_source["Ebene89"] = np.where(df_source["GuV"], df_source["Ebene80"], "")
  765. df_source["Ebene90"] = ""
  766. df_source["Ebene71"] = np.where(df_source["GuV"], "GuV", df_source["Ebene72"])
  767. df_source["Ebene72"] = np.where(df_source["GuV"], "", df_source["Ebene73"])
  768. df_source["Ebene73"] = np.where(df_source["GuV"], "", df_source["Ebene74"])
  769. df_source["Ebene74"] = np.where(df_source["GuV"], "", df_source["Ebene75"])
  770. df_source["Ebene75"] = np.where(df_source["GuV"], "", df_source["Ebene76"])
  771. df_source["Ebene76"] = np.where(df_source["GuV"], "", df_source["Ebene77"])
  772. df_source["Ebene77"] = np.where(df_source["GuV"], "", df_source["Ebene78"])
  773. df_source["Ebene78"] = np.where(df_source["GuV"], "", df_source["Ebene79"])
  774. df_source["Ebene79"] = np.where(df_source["GuV"], "", df_source["Ebene80"])
  775. df_source["Ebene80"] = ""
  776. df_source["Susa"] = df_source["Konto_Gruppe"].str.slice(stop=1)
  777. df_source["Konto_KST"] = ""
  778. df_source["GuV_Bilanz"] = np.where(df_source["GuV"], "2", "1")
  779. from_label = ["Konto_neu", "Konto_Nr_Händler", "Konto_Nr_Händler_kurz"]
  780. to_label = ["Konto", "Acct_Nr", "Konto_Nr_Händler"]
  781. df_source = df_source.rename(columns=dict(zip(from_label, to_label)))
  782. df_source = df_source[
  783. [
  784. "Konto",
  785. "Acct_Nr",
  786. "Konto_Bezeichnung",
  787. "GuV_Bilanz",
  788. "Konto_KST",
  789. "Konto_STK",
  790. "Konto_1",
  791. "Konto_2",
  792. "Konto_3",
  793. "Konto_4",
  794. "Konto_5",
  795. ]
  796. + get_default_cols(0)
  797. + get_default_cols(7)
  798. + get_default_cols(8)
  799. + get_default_cols(9)
  800. + [
  801. "Konto_Gruppe",
  802. "Konto_Nr_Gesamt",
  803. "Konto_Gesamt",
  804. "Susa",
  805. "Konto_Nr_Händler",
  806. "Konto_Händler",
  807. "Konto_mit_KST_Händler",
  808. ]
  809. ]
  810. df_source.to_csv(
  811. f"{self.config['path2']}/SKR51_Uebersetzung.csv",
  812. sep=";",
  813. encoding="latin-1",
  814. index=False,
  815. )
  816. is_quantity = df_source["Konto"].str.startswith("STK")
  817. df_source["Konto"] = np.where(
  818. is_quantity,
  819. df_source["Konto"].str.slice_replace(7, 9, "00"),
  820. df_source["Konto"].str.slice_replace(3, 5, "00"),
  821. )
  822. df_source["Acct_Nr"] = np.where(
  823. df_source["Acct_Nr"].str.contains("-"),
  824. df_source["Acct_Nr"].str.slice_replace(3, 5, "00"),
  825. df_source["Acct_Nr"],
  826. )
  827. df_department = df_source.drop_duplicates()
  828. df_department.to_csv(
  829. f"{self.config['path2']}/SKR51_Uebersetzung_ohne_Standort.csv",
  830. sep=";",
  831. encoding="latin-1",
  832. index=False,
  833. )
  834. def skr51_vars(self):
  835. self.get_structure_and_tree()
  836. cols = get_default_cols(0)
  837. df_temp = pd.read_csv(
  838. f"{self.config['path']}/Export/Kostentraeger.csv",
  839. decimal=",",
  840. sep=";",
  841. encoding="latin-1",
  842. converters={i: str for i in range(0, 200)},
  843. )
  844. df_temp["value"] = df_temp["Ebene33"]
  845. df_temp["key"] = "[KTR]"
  846. df_temp = df_temp[df_temp["value"].str.contains(" - ")]
  847. df_list = [df_temp[["key", "value"]]]
  848. for s, entries in self.json_result["flat"].items():
  849. df = pd.DataFrame([x["id"].split(";") for x in entries], columns=cols)
  850. df["key"] = df[cols[0]].apply(lambda x: "{" + s + "/" + x + "}")
  851. df["value"] = df[cols[1]]
  852. df_list.append(df[["key", "value"]])
  853. df = pd.concat(df_list)
  854. df_vars = df[df["value"] != ""]
  855. # df_vars.to_csv(f"{self.config['path2']}/SKR51_Variablen2.csv", sep=';', encoding='latin-1', index=False)
  856. df_main = pd.DataFrame(
  857. [x["id"].split(";") for x in self.json_result["flat"]["SKR51"]],
  858. columns=cols,
  859. )
  860. df_main["value"] = ""
  861. for c in cols:
  862. df_main = df_main.merge(df_vars, how="left", left_on=c, right_on="key", suffixes=(None, "_" + c))
  863. df_main[c] = np.where(df_main["value_" + c].isna(), df_main[c], df_main["value_" + c])
  864. df_amount = df_main[df_main["Ebene1"] == "Umsatzerlöse"].reset_index()
  865. df_amount["Ebene1"] = "verkaufte Stückzahlen"
  866. df_main = pd.concat([df_main, df_amount])
  867. # from_label = cols
  868. to_label = cols # get_default_cols(9)
  869. # df_main = df_main.rename(columns=dict(zip(from_label, to_label)))
  870. df_main[to_label].to_csv(
  871. f"{self.config['path2']}/SKR51_Struktur.csv",
  872. sep=";",
  873. encoding="latin-1",
  874. index_label="Sortierung",
  875. )
  876. def reisacher():
  877. base_dir = "X:/Robert/Planung Reisacher/GCStruct_neue_Struktur_Planung"
  878. if not Path(base_dir).exists():
  879. base_dir = "/media/fileserver1/austausch/Robert/Planung Reisacher/GCStruct_neue_Struktur_Planung"
  880. struct = GCStruct(base_dir)
  881. struct.get_structure_and_tree()
  882. struct.export_structure_and_tree()
  883. # json.dump(res['flat'], open(f"{self.config['path2']}/{self.config['output']}", 'w'), indent=2)
  884. if __name__ == "__main__":
  885. # struct = GCStruct('c:/projekte/gcstruct_dresen')
  886. # struct = GCStruct('c:/projekte/python/gcstruct')
  887. # struct = GCStruct('c:/projekte/python/gcstruct_reisacher_planung')
  888. reisacher()
  889. # dresen()