gcstruct.py 39 KB

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