gcstruct.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. import pandas as pd
  2. import numpy as np
  3. import xml.etree.ElementTree as ET
  4. import json
  5. import csv
  6. import re
  7. from bs4 import BeautifulSoup
  8. from functools import reduce
  9. config = {
  10. 'path': 'c:/projekte/python/gcstruct',
  11. 'path2': 'c:/projekte/python/gcstruct',
  12. 'output': 'gcstruct.json',
  13. 'default': [],
  14. 'special': {},
  15. 'special2': {
  16. 'Planner': ['Kostenstelle', 'Ebene1', 'Ebene2'],
  17. 'Test': ['Ebene1', 'Ebene2']
  18. },
  19. 'columns': ['Konto_Nr', 'Konto_Bezeichnung', 'Konto_Art', 'Konto_KST', 'Konto_STK', 'Konto_1', 'Konto_2', 'Konto_3', 'Konto_4', 'Konto_5'],
  20. 'struct': {}
  21. }
  22. json_result = {'accounts': {}, 'tree': {}, 'flat': {}, 'struct_export': {}, 'skr51_vars': {}}
  23. def get_tree_root(node, structure):
  24. id = ';' * 9
  25. return {
  26. 'id': id,
  27. 'text': node.attrib['Name'],
  28. 'children': get_tree(node, [], structure),
  29. 'parents': [],
  30. 'accounts': [],
  31. 'level': 0,
  32. 'form': ''
  33. }
  34. def get_tree(node, parents, structure):
  35. result = []
  36. for child in node:
  37. p = get_parents_list(parents)
  38. parents.append(child.attrib['Name'])
  39. id = ';'.join(parents) + ';' * (10 - len(parents))
  40. result.append({
  41. 'id': id,
  42. 'text': child.attrib['Name'],
  43. 'children': get_tree(child, parents, structure),
  44. 'parents': p,
  45. 'accounts': get_accounts(structure, id),
  46. 'level': len(parents),
  47. 'form': child.attrib.get('Split', '')
  48. })
  49. parents.pop()
  50. return result
  51. def get_flat(node):
  52. result = [{
  53. 'id': node['id'],
  54. 'text': node['text'],
  55. 'children': [x['id'] for x in node['children']],
  56. 'children2': [],
  57. 'parents': node['parents'],
  58. 'accounts': node['accounts'],
  59. 'costcenter': '',
  60. 'level': node['level'],
  61. 'drilldown': node['level'] < 2, # (node['level'] != 2 and len(node['accounts']) == 0),
  62. 'form': node['form'],
  63. 'accountlevel': False,
  64. 'absolute': True,
  65. 'seasonal': True,
  66. 'status': "0",
  67. 'values': [],
  68. 'values2': {}
  69. }]
  70. for child in node['children']:
  71. result += get_flat(child)
  72. return result
  73. def get_accounts(structure, id):
  74. return [x['Konto_Nr'] for x in json_result['accounts'] if x[structure] == id]
  75. def get_parents_list(p_list):
  76. id = ';'.join(p_list) + ';' * (10 - len(p_list))
  77. if len(p_list) > 0:
  78. return [id] + get_parents_list(p_list[:-1])
  79. return [';' * 9]
  80. def structure_from_tree(node):
  81. result = []
  82. result.append(node['id'])
  83. for child in node['children']:
  84. result.extend(structure_from_tree(child))
  85. return result
  86. def xml_from_tree(xml_node, tree_node):
  87. for child in tree_node['children']:
  88. element = ET.SubElement(xml_node, 'Ebene')
  89. element.set("Name", child['text'])
  90. xml_from_tree(element, child)
  91. def split_it(text, index):
  92. try:
  93. return re.findall(r'([^;]+) - ([^;]*);;', text)[0][index]
  94. except Exception:
  95. return ''
  96. def last_layer(text):
  97. try:
  98. return re.findall(r'([^;]+);;', text)[0]
  99. except Exception:
  100. return ''
  101. def get_default_cols(i):
  102. return ['Ebene' + str(i) for i in range(i * 10 + 1, (i + 1) * 10 + 1)]
  103. def accounts_from_csv(struct):
  104. max_rows = (len(config['default']) + 1) * 10
  105. with open(f"{config['path']}/Kontenrahmen/Kontenrahmen.csv", 'r', encoding='ansi') as f:
  106. csv_reader = csv.reader(f, delimiter=';')
  107. imported_csv = [row[:max_rows] for row in csv_reader]
  108. df = pd.DataFrame.from_records(np.array(imported_csv[1:], dtype='object'), columns=imported_csv[0]).fillna(value='')
  109. df = df.rename(columns={'Kostenstelle': 'Konto_KST', 'STK': 'Konto_STK'})
  110. for i, (s, cols) in enumerate(struct.items()):
  111. df[s] = reduce(lambda x, y: x + ";" + df[y], cols, '')
  112. df[s] = df[s].apply(lambda x: x[1:])
  113. df['LetzteEbene' + str(i + 1)] = df[s].apply(lambda x: last_layer(x))
  114. df['LetzteEbene' + str(i + 1) + '_Nr'] = df[s].apply(lambda x: split_it(x, 0))
  115. df['LetzteEbene' + str(i + 1) + '_Bez'] = df[s].apply(lambda x: split_it(x, 1))
  116. return df
  117. def tree_from_xml(struct, df):
  118. result = {}
  119. for (s, cols) in struct.items():
  120. try:
  121. tree = ET.parse(f"{config['path']}/Xml/{s}.xml")
  122. result[s] = get_tree_root(tree.getroot(), s)
  123. except FileNotFoundError:
  124. print('XML-Datei fehlt')
  125. used_entries = [x.split(";")[1:] for x in set(df[s].to_numpy())]
  126. print(used_entries)
  127. root = ET.Element('Ebene')
  128. root.set('Name', s)
  129. result[s] = get_tree_root(root, s)
  130. # json_result["tree"][s] = get_tree_from_accounts(cols, [])
  131. return result
  132. def get_structure_and_tree():
  133. df = accounts_from_csv(config['struct'])
  134. json_result['accounts'] = df.to_dict('records')
  135. json_result['tree'] = tree_from_xml(config['struct'], df)
  136. for (s, cols) in config['struct'].items():
  137. json_result['flat'][s] = get_flat(json_result['tree'][s])
  138. for (s, entries) in json_result['flat'].items():
  139. cols = config['struct'][s]
  140. df_temp = pd.DataFrame([x['id'].split(';') for x in entries], columns=cols)
  141. json_result['struct_export'][s] = df_temp.to_dict(orient='records')
  142. # json.dump(json_result, open(f"{config['path2']}/{config['output']}", 'w'), indent=2)
  143. return df
  144. def post_structure_and_tree():
  145. json_post = json.load(open(f"{config['path']}/{config['output']}", 'r'))
  146. # Kontenrahmen.csv
  147. ebenen = ['Ebene' + str(i) for i in range(1, len(config['default']) * 10 + 1)]
  148. header = ';'.join(config['columns'] + ebenen)
  149. cols = config['columns'] + config['default']
  150. with open(config['path'] + '/Kontenrahmen/Kontenrahmen_out.csv', 'w', encoding='ansi') as f:
  151. f.write(header + '\n')
  152. for row in json_post['Kontenrahmen']:
  153. f.write(';'.join([row[e] for e in cols]) + '\n')
  154. # print(header)
  155. # xml und evtl. Struktur.csv
  156. for i, s in enumerate(config['default']):
  157. with open(f"{config['path']}/Strukturen/Kontenrahmen.csv/{s}_out.csv", 'w', encoding='ansi') as f:
  158. f.write(';'.join(['Ebene' + str(i * 10 + j) for j in range(1, 11)]) + '\n')
  159. rows = structure_from_tree({'id': ";" * 9, 'children': json_post[s]})
  160. f.write('\n'.join(rows))
  161. # with open(config['path'] + "/Strukturen/Kontenrahmen.csv/" + structure + "_2.csv", "w", encoding="ansi") as f:
  162. root = ET.Element('Ebene')
  163. root.set('Name', s)
  164. xml_from_tree(root, {'id': ";" * 9, 'children': json_post[s]})
  165. with open(f"{config['path']}/Xml/{s}_out.xml", 'w', encoding='utf-8') as f:
  166. f.write(BeautifulSoup(ET.tostring(root), 'xml').prettify())
  167. def struct_config(struct_path):
  168. config['path'] = struct_path
  169. # config['path2'] = struct_path
  170. cfg = ET.parse(f"{config['path']}/config/config.xml")
  171. config['default'] = [s.find('Name').text for s in cfg.getroot().find('Strukturdefinitionen').findall('Struktur')]
  172. struct = dict([(x, get_default_cols(i)) for (i, x) in enumerate(config['default'])])
  173. struct.update(config['special'])
  174. config['struct'] = struct
  175. def skr51_translate():
  176. df = accounts_from_csv(config['struct'])
  177. translate = {'Konto_Nr': 'SKR51', 'Kostenstelle': 'KST', 'Absatzkanal': 'ABS', 'Kostenträger': 'KTR', 'Marke': 'MAR', 'Standort': 'STA'}
  178. df_translate = {}
  179. for i, (_, t_to) in enumerate(translate.items()):
  180. last = 'LetzteEbene' + str(i + 1)
  181. from_label = ['Konto_Nr', last, last + '_Nr', last + '_Bez', 'Ebene' + str(i * 10 + 1), 'Ebene' + str(i * 10 + 2)]
  182. to_label = [t_to, t_to + '_Ebene', t_to + '_Nr', t_to + '_Bez', 'Ebene1', 'Ebene2']
  183. df_translate[t_to] = df[df[last + '_Nr'] != ''][from_label].rename(columns=dict(zip(from_label, to_label)))
  184. # print(df_translate[t_to].head())
  185. df_source = pd.read_csv(f"{config['path']}/Export/Kontenrahmen_kombiniert.csv", decimal=',', sep=';', encoding='ansi', converters={i: str for i in range(0, 200)})
  186. for t_from, t_to in translate.items():
  187. if t_to == 'SKR51':
  188. df_source['SKR51'] = df_source['Konto_Nr']
  189. # print(df_translate[t_to].info())
  190. elif t_to == 'KTR':
  191. df_source['KTR'] = 'KTR_SC_' + df_source['Marke'] + '_' + df_source['Kostenträger']
  192. df_source['KTR'] = np.where(df_source['Ebene1_KST'] == 'Neuwagen', 'KTR_NW_' + df_source['Marke'] + '_' + df_source['Kostenträger'], df_source[t_to])
  193. df_source['KTR'] = np.where(df_source['Ebene1_KST'] == 'Teiledienst', 'KTR_TZ_' + df_source['Kostenträger'], df_source[t_to])
  194. else:
  195. df_source[t_to] = df_source[t_from].apply(lambda x: t_to + '_' + x)
  196. df_source = df_source.merge(df_translate[t_to], how='left', on=[t_to], suffixes=(None, '_' + t_to))
  197. df_source[t_to + '_Nr'] = np.where(df_source[t_to + '_Nr'].isna(), df_source[t_from], df_source[t_to + '_Nr'])
  198. # df_all[df_all['Ebene1'] == ]
  199. # print(df_source.head())
  200. df_source['Konto_Nr_SKR51'] = df_source['MAR_Nr'] + '-' + df_source['STA_Nr'] + '-' + df_source['SKR51_Nr'] + '-' + df_source['KST_Nr'] + '-' + df_source['ABS_Nr'] + '-' + df_source['KTR_Nr']
  201. df_source['Konto_Nr_Händler'] = df_source['Marke'] + '-' + df_source['Standort'] + '-' + df_source['Konto_Nr'] + '-' + df_source['Kostenstelle'] + '-' + df_source['Absatzkanal'] + '-' + df_source['Kostenträger']
  202. df_source.to_csv(f"{config['path2']}/SKR51_Uebersetzung.csv", sep=';', encoding='ansi', index=False)
  203. from_label = ['MAR_Nr', 'STA_Nr', 'SKR51_Nr', 'KST_Nr', 'ABS_Nr', 'KTR_Nr', 'KTR_Ebene', 'Konto_Nr_Händler']
  204. to_label = ['Marke', 'Standort', 'Konto_Nr', 'Kostenstelle', 'Absatzkanal', 'Kostenträger', 'Kostenträger_Ebene', 'Konto_Nr_Händler']
  205. df_combined = df_source[from_label].rename(columns=dict(zip(from_label, to_label)))
  206. df_combined.to_csv(f"{config['path2']}/Kontenrahmen_kombiniert.csv", sep=';', encoding='ansi', index=False)
  207. def skr51_translate2():
  208. df = accounts_from_csv(config['struct'])
  209. translate = {'Konto_Nr': 'SKR51', 'Kostenstelle': 'KST', 'Absatzkanal': 'ABS', 'Kostenträger': 'KTR', 'Marke': 'MAR', 'Standort': 'STA'}
  210. df_list = []
  211. for i, s in enumerate(config['struct'].keys()):
  212. from_label = ['Konto_Nr', 'Ebene' + str(i * 10 + 1), 'Ebene' + str(i * 10 + 2), 'Ebene' + str(i * 10 + 3)]
  213. to_label = ['Konto_Nr', 'key', 'value', 'value2']
  214. df_temp = df[from_label].rename(columns=dict(zip(from_label, to_label)))
  215. df_temp['key'] = '{' + s + '/' + df_temp['key'] + '}'
  216. df_list.append(df_temp[df_temp['value'] != ''])
  217. df_translate = pd.concat(df_list)
  218. print(df_translate.head())
  219. df_source = pd.read_csv(f"{config['path']}/Export/Kontenrahmen_kombiniert.csv", decimal=',', sep=';', encoding='ansi', converters={i: str for i in range(0, 200)})
  220. df_source = df_source.merge(df, how='left', on=['Konto_Nr'])
  221. rows = df_source.shape[0]
  222. df_source['value'] = ''
  223. for t_from, t_to in translate.items():
  224. df_source[t_to] = t_to + '_' + df_source[t_from]
  225. for e in config['struct']['SKR51']:
  226. df_source = df_source.merge(df_translate, how='left', left_on=[t_to, e], right_on=['Konto_Nr', 'key'], suffixes=(None, '_' + t_to + '_' + e))
  227. df_source[e] = np.where(df_source['value_' + t_to + '_' + e].notna(), df_source['value_' + t_to + '_' + e], df_source[e])
  228. if df_source.shape[0] > rows:
  229. print(t_to + '_' + e + ': ' + str(df_source.shape[0]))
  230. # df_source[t_to + '_Nr'] = np.where(df_source[t_to + '_Nr'].isna(), df_source[t_from], df_source[t_to + '_Nr'])
  231. for e in config['struct']['SKR51']:
  232. # df_source[e] = np.where(df_source[e].str.startswith('{'), 'falsch', df_source[e]) # df_source[e].str.extract(r'/(.*)}') +
  233. df_source[e] = np.where(df_source[e] == '[KTR]', df_source['Kostenträger_Ebene'], df_source[e])
  234. # df_all[df_all['Ebene1'] == ]
  235. print(df_source.head())
  236. df_source['Konto_neu'] = df_source['Marke'] + '-' + df_source['Standort'] + '-' + df_source['Konto_Nr'] + '-' + df_source['Kostenstelle'] + '-' + df_source['Absatzkanal'] + '-' + df_source['Kostenträger'] + ' - ' + df_source['Konto_Bezeichnung']
  237. df_source = df_source[['Konto', 'Konto_Nr_Händler', 'Konto_Bezeichnung', 'Konto_Art', 'Konto_KST', 'Konto_STK', 'Konto_1', 'Konto_2', 'Konto_3', 'Konto_4', 'Konto_5', 'Ebene1', 'Ebene2', 'Ebene3', 'Ebene4', 'Ebene5', 'Ebene6', 'Ebene7', 'Ebene8', 'Ebene9', 'Ebene10']]
  238. from_label = get_default_cols(0)
  239. to_label = get_default_cols(9)
  240. df_source = df_source.rename(columns=dict(zip(from_label, to_label)))
  241. # 'Marke', 'Standort', 'Konto_Nr', 'Kostenstelle', 'Absatzkanal', 'Kostenträger',
  242. df_source.to_csv(f"{config['path2']}/SKR51_Uebersetzung.csv", sep=';', encoding='ansi', index=False)
  243. # df_source['Konto_Nr_SKR51'] = df_source['MAR_Nr'] + '-' + df_source['STA_Nr'] + '-' + df_source['SKR51_Nr'] + '-' + df_source['KST_Nr'] + '-' + df_source['ABS_Nr'] + '-' + df_source['KTR_Nr']
  244. # from_label = ['MAR_Nr', 'STA_Nr', 'SKR51_Nr', 'KST_Nr', 'ABS_Nr', 'KTR_Nr', 'KTR_Ebene', 'Konto_Nr_Händler']
  245. # to_label = ['Marke', 'Standort', 'Konto_Nr', 'Kostenstelle', 'Absatzkanal', 'Kostenträger', 'Kostenträger_Ebene', 'Konto_Nr_Händler']
  246. # df_combined = df_source[from_label].rename(columns=dict(zip(from_label, to_label)))
  247. # df_combined.to_csv(f"{config['path2']}/Kontenrahmen_kombiniert.csv", sep=';', encoding='ansi', index=False)
  248. def skr51_vars():
  249. get_structure_and_tree()
  250. cols = get_default_cols(0)
  251. df_list = []
  252. for (s, entries) in json_result['flat'].items():
  253. df = pd.DataFrame([x['id'].split(';') for x in entries], columns=cols)
  254. df['key'] = df[cols[0]].apply(lambda x: '{' + s + '/' + x + '}')
  255. df['value'] = df[cols[1]]
  256. df_list.append(df[['key', 'value']])
  257. df = pd.concat(df_list)
  258. df_vars = df[df['value'] != '']
  259. df_main = pd.DataFrame([x['id'].split(';') for x in json_result['flat']['SKR51']], columns=cols)
  260. df_main['value'] = ''
  261. for c in cols:
  262. df_main = df_main.merge(df_vars, how='left', left_on=c, right_on='key', suffixes=(None, '_' + c))
  263. df_main[c] = np.where(df_main['value_' + c].isna(), df_main[c], df_main['value_' + c])
  264. df_main[cols].to_csv(f"{config['path2']}/SKR51_Struktur.csv", sep=';', encoding='ansi', index_label='Sortierung')
  265. if __name__ == '__main__':
  266. # struct_config('c:/projekte/gcstruct_dresen')
  267. # struct_config('c:/projekte/python/gcstruct')
  268. # struct_config('c:/projekte/python/gcstruct_reisacher_planung')
  269. # struct_config('X:/Robert/Planung Reisacher/GCStruct_neue_Struktur_Planung')
  270. # struct_config('P:/SKR51_GCStruct/GCStruct_Siebrecht')
  271. struct_config('P:/SKR51_GCStruct/GCStruct_Portal')
  272. # print(config['struct'])
  273. # get_structure_and_tree()
  274. # post_structure_and_tree()
  275. # skr51_translate()
  276. skr51_translate2()
  277. # skr51_vars()