浏览代码

- GCStruct neue Verarbeitung
- csv_update.py Abgleich evtl. mit Beibehaltung von Einträgen
- Mailversand nachgebaut
- Squareroot Quiz

Robert Bedner 4 年之前
父节点
当前提交
8a73f60730
共有 10 个文件被更改,包括 303 次插入170 次删除
  1. 10 4
      csv_update.py
  2. 100 113
      gcstruct.py
  3. 38 0
      gctools/config.py
  4. 65 0
      gctools/dispatch.py
  5. 二进制
      gctools/gctools.zip
  6. 65 0
      gctools/mail.py
  7. 5 5
      gctools/publish-reports.mac
  8. 0 46
      mail.py
  9. 17 0
      squareroot.py
  10. 3 2
      status-server.py

+ 10 - 4
csv_update.py

@@ -1,9 +1,12 @@
 import pandas as pd
 from functools import reduce
 
-source_csv = 'data\\Kontenrahmen_Import.csv'
-target_csv = 'data\\Kontenrahmen.csv'
-result_csv = 'data\\Kontenrahmen_Ergebnis.csv'
+# source_csv = 'data\\Kontenrahmen_Import.csv'
+# target_csv = 'data\\Kontenrahmen.csv'
+# result_csv = 'data\\Kontenrahmen_Ergebnis.csv'
+source_csv = 'P:\\SKR51_GCStruct\\Kontenrahmen_Vorlage.csv'
+target_csv = 'P:\\SKR51_GCStruct\\GCStruct_Portal\\Kontenrahmen\\Kontenrahmen.csv'
+result_csv = 'P:\\SKR51_GCStruct\\GCStruct_Portal\\Kontenrahmen\\Kontenrahmen_neu.csv'
 
 debug = False
 cols_pkey = ['Konto_Nr']
@@ -29,7 +32,10 @@ target_columns = df_target.columns
 df_target['pkey'] = reduce(lambda x, y: x + "_" + df_target[y], cols_pkey, "")
 df_target = df_target.set_index('pkey')
 
-df_join = df_source.join(df_target, rsuffix='_other')[target_columns]
+df_join = df_source.join(df_target, how='left', rsuffix='_other')[target_columns]
+df_remain = df_target.join(df_source, how='left', rsuffix='_other')
+df_remain = df_remain[pd.isna(df_remain[cols_pkey[0] + '_other'])][target_columns]
 # df_result = df_join[(df_join['Gesamt'] != 0) & (df_join['Serviceberater'] != "")]
+# df_join = df_join.append(df_remain).sort_index()
 
 df_join.to_csv(result_csv, decimal=",", sep=";", encoding="ansi", index=None)

+ 100 - 113
gcstruct.py

@@ -7,71 +7,34 @@ import re
 from bs4 import BeautifulSoup
 from functools import reduce
 
-reisacher = False
-reisacher_remote = False
-dresen = True
-
 
 config = {
-    'path': "c:/projekte/python/gcstruct",
-    'path2': "c:/projekte/python/gcstruct",
-    'output': "gcstruct.json",
-    'default': ["SKR51", "Herkunft_KST", "Absatzkanal", "Kostentraeger", "Marke", "Standort", "Manuelle_Konten"],
-    'special': {
-        'Planner': ["Kostenstelle", "Ebene1", "Ebene2"],
-        'Test': ["Ebene1", "Ebene2"]
+    'path': 'c:/projekte/python/gcstruct',
+    'path2': 'c:/projekte/python/gcstruct',
+    'output': 'gcstruct.json',
+    'default': [],
+    'special': {},
+    'special2': {
+        'Planner': ['Kostenstelle', 'Ebene1', 'Ebene2'],
+        'Test': ['Ebene1', 'Ebene2']
     }
 }
 
-if reisacher:
-    config = {
-        'path': "c:/projekte/python/gcstruct_reisacher_planung",
-        'path2': "c:/projekte/python/gcstruct_reisacher_planung",
-        'output': "gcstruct_reisacher.json",
-        'default': ["Struktur_FB", "Struktur_TEK", "Struktur_GuV", "Struktur_Bilanz", "Struktur_HBV", "Bruttoertrag"],
-        'special': {
-            'Planner': ["Kostenstelle", "Ebene1", "Ebene2"],
-            'Test': ["Ebene1", "Ebene2"]
-        }
-    }
+columns = ['Konto_Nr', 'Konto_Bezeichnung', 'Konto_Art', 'Konto_KST', 'Konto_STK', 'Konto_1', 'Konto_2', 'Konto_3', 'Konto_4', 'Konto_5']
 
-if reisacher_remote:
-    config = {
-        'path': "X:/Robert/Planung Reisacher/GCStruct_neue_Struktur_Planung",
-        'path2': "C:/Projekte/Angular/gc-form/src/assets/data",
-        'output': "gcstruct_reisacher.json",
-        'default': ["Struktur_FB", "Struktur_TEK", "Struktur_GuV", "Struktur_Bilanz", "Struktur_HBV", "Bruttoertrag"],
-        'special': {
-            'Planner': ["Kostenstelle", "Ebene1", "Ebene2"],
-            'Test': ["Ebene1", "Ebene2"]
-        }
-    }
-
-if dresen:
-    config = {
-        'path': "c:/projekte/gcstruct_dresen",
-        'path2': "c:/projekte/gcstruct_dresen",
-        'output': "gcstruct.json",
-        'default': ["Struktur_FB", "Struktur_TEK", "Struktur_GuV", "Struktur_3"],
-        'special': {}
-    }
-
-
-columns = ["Konto_Nr", "Konto_Bezeichnung", "Konto_Art", "Kostenstelle", "STK", "Konto_1", "Konto_2", "Konto_3", "Konto_4", "Konto_5"]
-
-json_result = {"accounts": {}, "tree": {}, "flat": {}}
+json_result = {'accounts': {}, 'tree': {}, 'flat': {}}
 
 
 def get_tree_root(node, structure):
-    id = ";" * 9
+    id = ';' * 9
     return {
-        "id": id,
-        "text": node.attrib['Name'],
-        "children": get_tree(node, [], structure),
-        "parents": [],
-        "accounts": [],
-        "level": 0,
-        "form": ''
+        'id': id,
+        'text': node.attrib['Name'],
+        'children': get_tree(node, [], structure),
+        'parents': [],
+        'accounts': [],
+        'level': 0,
+        'form': ''
     }
 
 
@@ -80,15 +43,15 @@ def get_tree(node, parents, structure):
     for child in node:
         p = get_parents_list(parents)
         parents.append(child.attrib['Name'])
-        id = ";".join(parents) + ";" * (10 - len(parents))
+        id = ';'.join(parents) + ';' * (10 - len(parents))
         result.append({
-            "id": id,
-            "text": child.attrib['Name'],
-            "children": get_tree(child, parents, structure),
-            "parents": p,
-            "accounts": get_accounts(structure, id),
-            "level": len(parents),
-            "form": child.attrib.get('Split', '')
+            'id': id,
+            'text': child.attrib['Name'],
+            'children': get_tree(child, parents, structure),
+            'parents': p,
+            'accounts': get_accounts(structure, id),
+            'level': len(parents),
+            'form': child.attrib.get('Split', '')
         })
         parents.pop()
     return result
@@ -96,22 +59,22 @@ def get_tree(node, parents, structure):
 
 def get_flat(node):
     result = [{
-        "id": node['id'],
-        "text": node['text'],
-        "children": [x['id'] for x in node['children']],
-        "children2": [],
-        "parents": node['parents'],
-        "accounts": node['accounts'],
-        "costcenter": "",
-        "level": node['level'],
-        "drilldown": node['level'] < 2,    # (node['level'] != 2 and len(node['accounts']) == 0),
-        "form": node['form'],
-        "accountlevel": False,
-        "absolute": True,
-        "seasonal": True,
-        "status": "0",
-        "values": [],
-        "values2": {}
+        'id': node['id'],
+        'text': node['text'],
+        'children': [x['id'] for x in node['children']],
+        'children2': [],
+        'parents': node['parents'],
+        'accounts': node['accounts'],
+        'costcenter': '',
+        'level': node['level'],
+        'drilldown': node['level'] < 2,    # (node['level'] != 2 and len(node['accounts']) == 0),
+        'form': node['form'],
+        'accountlevel': False,
+        'absolute': True,
+        'seasonal': True,
+        'status': "0",
+        'values': [],
+        'values2': {}
     }]
     for child in node['children']:
         result += get_flat(child)
@@ -123,10 +86,10 @@ def get_accounts(structure, id):
 
 
 def get_parents_list(p_list):
-    id = ";".join(p_list) + ";" * (10 - len(p_list))
+    id = ';'.join(p_list) + ';' * (10 - len(p_list))
     if len(p_list) > 0:
         return [id] + get_parents_list(p_list[:-1])
-    return [";" * 9]
+    return [';' * 9]
 
 
 def structure_from_tree(node):
@@ -139,40 +102,50 @@ def structure_from_tree(node):
 
 def xml_from_tree(xml_node, tree_node):
     for child in tree_node['children']:
-        element = ET.SubElement(xml_node, "Ebene")
+        element = ET.SubElement(xml_node, 'Ebene')
         element.set("Name", child['text'])
         xml_from_tree(element, child)
 
 
 def split_it(text, index):
     try:
-        return re.findall(r"([^;]+) - ([^;]*);;", text)[0][index]
+        return re.findall(r'([^;]+) - ([^;]*);;', text)[0][index]
+    except Exception:
+        return ''
+
+
+def last_layer(text):
+    try:
+        return re.findall(r'([^;]+);;', text)[0]
     except Exception:
-        return ""
+        return ''
 
 
 def get_default_cols(i):
-    return ["Ebene" + str(i) for i in range(i * 10 + 1, (i + 1) * 10 + 1)]
+    return ['Ebene' + str(i) for i in range(i * 10 + 1, (i + 1) * 10 + 1)]
 
 
 def get_structure_and_tree(struct):
+    max_rows = (len(config['default']) + 1) * 10
     with open(f"{config['path']}/Kontenrahmen/Kontenrahmen.csv", 'r', encoding='ansi') as f:
         csv_reader = csv.reader(f, delimiter=';')
-        imported_csv = [row[:50] for row in csv_reader]
+        imported_csv = [row[:max_rows] for row in csv_reader]
 
     # df = pd.read_csv(f"{config['path']}/Kontenrahmen/Kontenrahmen.csv", sep=";", encoding="ansi", quoting=3, converters={i: str for i in range(200)})    # , index_col="Konto_Nr")
     df = pd.DataFrame.from_records(np.array(imported_csv[1:], dtype='object'), columns=imported_csv[0]).fillna(value='')
-    print(df.head())
+    df = df.rename(columns={'Kostenstelle': 'Konto_KST', 'STK': 'Konto_STK'})
+    # print(df.head())
 
     for i, (s, cols) in enumerate(struct.items()):
-        df[s] = reduce(lambda x, y: x + ";" + df[y], cols, "")
+        df[s] = reduce(lambda x, y: x + ";" + df[y], cols, '')
         df[s] = df[s].apply(lambda x: x[1:])
+        df['LetzteEbene' + str(i + 1)] = df[s].apply(lambda x: last_layer(x))
         df['LetzteEbene' + str(i + 1) + '_Nr'] = df[s].apply(lambda x: split_it(x, 0))
         df['LetzteEbene' + str(i + 1) + '_Bez'] = df[s].apply(lambda x: split_it(x, 1))
 
-    len_items = len(struct)
-    df = df[columns + [*struct] + ['LetzteEbene' + str(i + 1) + '_Nr' for i in range(len_items)] + ['LetzteEbene' + str(i + 1) + '_Bez' for i in range(len_items)]]
-    json_result["accounts"] = df.to_dict("records")
+    # len_items = len(struct)
+    # df = df[columns + [*struct] + ['LetzteEbene' + str(i + 1) + '_Nr' for i in range(len_items)] + ['LetzteEbene' + str(i + 1) + '_Bez' for i in range(len_items)] + ['LetzteEbene' + str(i + 1) for i in range(len_items)]]
+    json_result['accounts'] = df.to_dict('records')
 
     # df2 = pd.read_csv("config['path'] + "/Strukturen/Kontenrahmen.csv/SKR51.csv", sep=";", encoding="ansi", decimal=",", converters={i: str for i in range(0, 200)})
     # print(df2.head())
@@ -183,50 +156,64 @@ def get_structure_and_tree(struct):
             json_result["tree"][s] = get_tree_root(tree.getroot(), s)
 
         except FileNotFoundError:
-            print("XML-Datei fehlt")
+            print('XML-Datei fehlt')
             used_entries = [x.split(";")[1:] for x in set(df[s].to_numpy())]
             print(used_entries)
-            root = ET.Element("Ebene")
-            root.set("Name", s)
-            json_result["tree"][s] = get_tree_root(root, s)
+            root = ET.Element('Ebene')
+            root.set('Name', s)
+            json_result['tree'][s] = get_tree_root(root, s)
             # json_result["tree"][s] = get_tree_from_accounts(cols, [])
 
-        json_result["flat"][s] = get_flat(json_result["tree"][s])
+        json_result['flat'][s] = get_flat(json_result['tree'][s])
 
-    json.dump(json_result, open(f"{config['path2']}/{config['output']}", "w"), indent=2)
+    json.dump(json_result, open(f"{config['path2']}/{config['output']}", 'w'), indent=2)
 
 
 def post_structure_and_tree():
-    json_post = json.load(open(f"{config['path']}/{config['output']}", "r"))
+    json_post = json.load(open(f"{config['path']}/{config['output']}", 'r'))
 
     # Kontenrahmen.csv
-    ebenen = ["Ebene" + str(i) for i in range(1, len(config['default']) * 10 + 1)]
-    header = ";".join(columns + ebenen)
+    ebenen = ['Ebene' + str(i) for i in range(1, len(config['default']) * 10 + 1)]
+    header = ';'.join(columns + ebenen)
     cols = columns + config['default']
-    with open(config['path'] + "/Kontenrahmen/Kontenrahmen_out.csv", "w", encoding="ansi") as f:
-        f.write(header + "\n")
+    with open(config['path'] + '/Kontenrahmen/Kontenrahmen_out.csv', 'w', encoding='ansi') as f:
+        f.write(header + '\n')
         for row in json_post['Kontenrahmen']:
-            f.write(";".join([row[e] for e in cols]) + "\n")
+            f.write(';'.join([row[e] for e in cols]) + '\n')
     # print(header)
     # xml und evtl. Struktur.csv
     for i, s in enumerate(config['default']):
-        with open(config['path'] + "/Strukturen/Kontenrahmen.csv/" + s + "_out.csv", "w", encoding="ansi") as f:
-            f.write(";".join(["Ebene" + str(i * 10 + j) for j in range(1, 11)]) + "\n")
-            rows = structure_from_tree({"id": ";" * 9, "children": json_post[s]})
-            f.write("\n".join(rows))
+        with open(f"{config['path']}/Strukturen/Kontenrahmen.csv/{s}_out.csv", 'w', encoding='ansi') as f:
+            f.write(';'.join(['Ebene' + str(i * 10 + j) for j in range(1, 11)]) + '\n')
+            rows = structure_from_tree({'id': ";" * 9, 'children': json_post[s]})
+            f.write('\n'.join(rows))
 
         # with open(config['path'] + "/Strukturen/Kontenrahmen.csv/" + structure + "_2.csv", "w", encoding="ansi") as f:
-        root = ET.Element("Ebene")
-        root.set("Name", s)
-        xml_from_tree(root, {"id": ";" * 9, "children": json_post[s]})
+        root = ET.Element('Ebene')
+        root.set('Name', s)
+        xml_from_tree(root, {'id': ";" * 9, 'children': json_post[s]})
 
-        with open(config['path'] + "/Xml/" + s + "_out.xml", "w", encoding="utf-8") as f:
-            f.write(BeautifulSoup(ET.tostring(root), "xml").prettify())
+        with open(f"{config['path']}/Xml/{s}_out.xml", 'w', encoding='utf-8') as f:
+            f.write(BeautifulSoup(ET.tostring(root), 'xml').prettify())
 
 
-if __name__ == '__main__':
+def main(struct_path):
+    config['path'] = struct_path
+    # config['path2'] = struct_path
+
+    cfg = ET.parse(f"{config['path']}/config/config.xml")
+    config['default'] = [s.find('Name').text for s in cfg.getroot().find('Strukturdefinitionen').findall('Struktur')]
+
     struct = dict([(x, get_default_cols(i)) for (i, x) in enumerate(config['default'])])
     struct.update(config['special'])
     print(struct)
     get_structure_and_tree(struct)
     # post_structure_and_tree()
+
+
+if __name__ == '__main__':
+    # main('c:/projekte/gcstruct_dresen')
+    main('P:\\SKR51_GCStruct\\GCStruct_Siebrecht')
+    # main('c:/projekte/python/gcstruct')
+    # "c:/projekte/python/gcstruct_reisacher_planung",
+    # "X:/Robert/Planung Reisacher/GCStruct_neue_Struktur_Planung"

+ 38 - 0
gctools/config.py

@@ -1,3 +1,8 @@
+from collections import namedtuple
+
+MailConfig = namedtuple('MailConfig', 'server port secure username password email')
+
+
 class config:
     portal_dir = 'C:\\GAPS\\Portal'
     tasks_dir = portal_dir + '\\Tasks'
@@ -5,3 +10,36 @@ class config:
     log_dir = tasks_dir + '\\logs'
     cognos_dir = 'C:\\Program Files (x86)\\Cognos\\cer5\\bin'
     tools_dir = 'C:\\Projekte\\Python\\gctools'
+    kunde = 'Test'
+    versand_separat = False
+
+    def __init__(self):
+        cfg = {}
+        with open(self.tasks_dir + '\\GAPS.ini', 'r') as stream:
+            for line in stream.readlines():
+                if '=' in line:
+                    key, value = line.split('=')
+                    cfg[key] = value.replace('"', '').replace('\n', '')
+        self.kunde = cfg.get('KUNDE', 'Test')
+
+        self.smtp = MailConfig(**{
+            'server': 'smtp.ionos.de',
+            'port': '465',
+            'secure': 'ssl',
+            'username': 'versand@global-cube.de',
+            'password': 'gc01smtp',
+            'email': 'versand@global-cube.de'
+        })
+        if 'SMTP_HOST' in cfg and cfg['SMTP_HOST'] != '':
+            secure = {'': '', 'N': '', 'J': 'ssl', 'SSL': 'ssl', 'TLS': 'tls'}
+
+            self.smtp = MailConfig(**{
+                'server': cfg.get('SMTP_HOST'),
+                'port': cfg.get('SMTP_PORT'),
+                'secure': secure[cfg.get('SMTP_SSL', '')],
+                'username': cfg.get('SMTP_USER'),
+                'password': cfg.get('SMTP_PW'),
+                'email': cfg.get('SMTP_FROM'),
+            })
+        if 'VERSAND_SEPARAT' in cfg:
+            self.versand_separat = cfg['VERSAND_SEPARAT'] == 'J'

+ 65 - 0
gctools/dispatch.py

@@ -0,0 +1,65 @@
+import pandas as pd
+from pathlib import Path
+from mail import mail
+import config
+
+cfg = config.config()
+report_dir = cfg.portal_dir + '\\System\\Report'
+publish_dir = cfg.portal_dir + '\\Publish\\daten'
+
+
+def html_mail(content):
+    html = """
+        <!DOCTYPE html>
+        <html><head>
+            <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+            <style>
+                .liste { border: 1px solid #888888; border-collapse: collapse; }
+                .liste td, .liste th { padding: 3px 15px; border: 1px solid #888888; }
+            </style>
+        </head><body>
+            <table class="liste"><tr><th>Datei</th><th>Bericht</th><th>Schicht</th><th>Stand</th><th>Empf&auml;nger</th></tr>
+            {0}
+            </table>
+        </body></html> """
+    return html.replace('{0}', content)
+
+
+xml_filename = 'GAPS_Vers_taeglich_MO'
+publish_subdir = publish_dir + '\\' + xml_filename
+xml_filename = xml_filename.lower() + '.xml'
+
+df = pd.read_csv(cfg.xml_dir + '\\info\\versand.csv', sep=';')
+xml_filter = (df['Datei'].str.lower() == xml_filename) & (df['Versand'] == 'J')
+df = df[xml_filter]
+report_mails = df.groupby(['Report', 'PDF-Schicht']).agg(lambda x: ',<br/> '.join(x))['Empfaenger']
+mail_batch = []
+
+for group_name, df_group in df.groupby('Empfaenger'):
+    group_table = []
+    group_filenames = []
+    for i, row in df_group.iterrows():
+        filename = f"{publish_subdir}\\{row['Report']}_{row['PDF-Schicht']}"
+        filename = filename + '.xls' if row['XLS'] == 'J' else filename + '.pdf'
+
+        row['Empfaenger'] = report_mails.at[row['Report'], row['PDF-Schicht']]
+        row['Dateiname'] = []
+        row['Stand'] = 'nicht verf&uuml;gbar'
+        if Path(filename).exists():
+            row['Stand'] = Path(filename).stat().st_mtime
+            row['Dateiname'].append((row['Name'], filename))
+            group_filenames.append((row['Name'], filename))
+
+        table_row = f"<tr><td>{row['Name']}</td><td>{row['Report']}</td><td>{row['PDF-Schicht']}</td><td>{row['Stand']}</td><td>{row['Empfaenger']}</td></tr>"
+        group_table.append(table_row)
+
+        if cfg.versand_separat:
+            mail_batch.append((group_name, row['Name'], html_mail(table_row), row['Dateiname']))
+
+    if not cfg.versand_separat:
+        mail_batch.append((group_name, 'GAPS-Versand', html_mail(''.join(group_table)), group_filenames))
+
+
+with mail() as m:
+    for e in mail_batch:
+        m.send(*e)

二进制
gctools/gctools.zip


+ 65 - 0
gctools/mail.py

@@ -0,0 +1,65 @@
+import smtplib
+import ssl
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.application import MIMEApplication
+import config
+
+
+class mail:
+    mail_cfg2 = config.MailConfig(**{
+        'server': 'mail.psmanaged.com',
+        'port': '465',
+        'secure': 'ssl',
+        'username': 'gc@scharf-automobile.de',
+        'password': '+Js10TnD*km4E6',
+        'email': 'gc@scharf-automobile.de'
+    })
+
+    def __init__(self):
+        self.cfg = config.config()
+        self.mail_cfg = self.cfg.smtp
+        self.reply_to = self.cfg.kunde.replace(' ', '-').lower() + '@global-cube.de'
+        self.context = ssl.create_default_context()
+
+    def __enter__(self):
+        try:
+            self.mailserver = smtplib.SMTP_SSL(self.mail_cfg.server, self.mail_cfg.port, context=self.context)
+            self.mailserver.login(self.mail_cfg.username, self.mail_cfg.password)
+        except smtplib.SMTPException as e:
+            print(e)
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.mailserver.quit()
+
+    def send(self, mailto, subject, html, attachment=None):
+        msg = self.message(mailto, subject, html, attachment)
+
+        try:
+            result = self.mailserver.sendmail(self.reply_to, mailto, msg.as_string())
+            print(result)
+        except smtplib.SMTPException as e:
+            print(e)
+
+    def message(self, mailto, subject, html, attachment):
+        msg = MIMEMultipart('alternative')
+        msg['Reply-To'] = self.reply_to
+        msg['From'] = f'Global Cube <{self.mail_cfg.email}>'
+        msg['To'] = mailto
+        msg['Subject'] = subject
+
+        # msg.attach(MIMEText(text, 'plain'))
+        msg.attach(MIMEText(html, 'html'))
+
+        for name, filename in attachment or []:
+            with open(filename, "rb") as f:
+                part = MIMEApplication(f.read(), Name=name)
+                part['Content-Disposition'] = f'attachment; filename="{name}"'
+                msg.attach(part)
+        return msg
+
+
+if __name__ == '__main__':
+    with mail() as m:
+        m.send('robert.bedner@gmail.com', 'Test 123', ['C:\\GAPS\\Portal\\daten\\1_1_Taegliche_Erfolgskontrolle_1.pdf'])

+ 5 - 5
gctools/publish-reports.mac

@@ -41,13 +41,13 @@ Sub Main ()
                For i = 1 to objRep.Layers.Count
                   Set objPDF = objRep.PDFFile(exportFile + "_" + i + ".pdf", True)
                   With objPDF
-                     .SaveEntireReport = False
-                     .SaveAllCharts = False                     
-                     .AxisOnAllPages = True
-                     .ChartTitleOnAllPages = False
-                     .IncludeLegend = False
                      .SetListOfLayersToSave objRep.Layers.Subset(i, i)
                      .SetListOfRowsToSave objRep.Rows
+                     .SaveEntireReport = False
+                     .SaveAllCharts = False           
+                     .AxisOnAllPages = True
+                     .ChartTitleOnAllPages = True
+                     .IncludeLegend = True
                   End With
                   objPDF.Save
                Next

+ 0 - 46
mail.py

@@ -1,46 +0,0 @@
-import smtplib
-import ssl
-from email.mime.text import MIMEText
-from email.mime.multipart import MIMEMultipart
-from collections import namedtuple
-
-MailConfig = namedtuple('MailConfig', 'server port secure username password email')
-
-mail_cfg = MailConfig(**{
-    'server': 'smtp.ionos.de',
-    'port': '465',
-    'secure': 'ssl',
-    'username': 'versand@global-cube.de',
-    'password': 'gc01smtp??',
-    'email': 'versand@global-cube.de'
-})
-mail_cfg = MailConfig(**{
-    'server': 'mail.psmanaged.com',
-    'port': '465',
-    'secure': 'ssl',
-    'username': 'gc@scharf-automobile.de',
-    'password': '+Js10TnD*km4E6',
-    'email': 'gc@scharf-automobile.de'
-})
-# receiver_email = 'bedner@global-cube.de'
-receiver_email = 'robert.bedner@gmail.com'
-
-context = ssl.create_default_context()
-
-message = MIMEMultipart('alternative')
-message['Subject'] = 'GAPS Mailversand'
-message['From'] = f'Global Cube <{mail_cfg.email}>'
-message['To'] = receiver_email
-text = 'Das ist der alternative Text. Auch okay, oder?!'
-html = '<html><body><h1>Coole Überschrift</h1><p>Und so geht es weiter. Gut lesbar?</p></body></html>'
-
-message.attach(MIMEText(text, 'plain'))
-message.attach(MIMEText(html, 'html'))
-
-try:
-    with smtplib.SMTP_SSL(mail_cfg.server, mail_cfg.port, context=context) as mailserver:
-        mailserver.login(mail_cfg.username, mail_cfg.password)
-        result = mailserver.sendmail(mail_cfg.email, receiver_email, message.as_string())
-        print(result)
-except smtplib.SMTPException as e:
-    print(e)

+ 17 - 0
squareroot.py

@@ -0,0 +1,17 @@
+from random import shuffle
+
+score = 0
+print('0 für Ende.')
+sqrt_list = [x for x in range(11, 101) if x % 10 != 0]
+shuffle(sqrt_list)
+
+for sq in sqrt_list:
+    print('Quadratwurzel von ' + str(sq**2) + '?')
+    x = int(input())
+    if x == 0:
+        break
+    elif x == sq:
+        score += 1
+        print('Richtig. Neuer Punktestand: ' + str(score))
+    else:
+        print('Falsch. Besser: ' + str(sq))

+ 3 - 2
status-server.py

@@ -3,8 +3,9 @@ from sqlalchemy import create_engine
 from datetime import datetime
 
 app = Flask(__name__)
-engine = create_engine('mysql+pymysql://gaps:Gcbs12ma@192.168.2.41/status')
 filename = 'access.log'
+engine = create_engine('mysql+pymysql://gaps:Gcbs12ma@192.168.2.41/status')
+
 
 @app.route("/ping/<kunde>")
 def ping(kunde):
@@ -15,5 +16,5 @@ def ping(kunde):
         f.write(str(current_date) + ';' + kunde + '\n')
     with engine.connect() as con:
         query = f"INSERT INTO ping (kunde, pingtime, uptime) VALUES ('{kunde}', '{int(current_date)}', '{uptime}')"
-        rs = con.execute(query)
+        con.execute(query)
     return 'Hallo ' + kunde + '!'