import mysql.connector from docx import Document from datetime import datetime from docx.shared import Pt from docx.oxml.ns import qn from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK from docx.enum.table import WD_ALIGN_VERTICAL from docx.oxml import OxmlElement import os from datetime import datetime, timedelta from dotenv import load_dotenv from dateutil.relativedelta import relativedelta load_dotenv() def fetch_tickets_from_database(): # Verbindung zur Datenbank herstellen mydb = mysql.connector.connect( host=os.getenv("MYSQL_HOST"), user=os.getenv("MYSQL_USER"), password=os.getenv("MYSQL_PASSWORD"), database=os.getenv("MYSQL_DATABASE") ) cursor = mydb.cursor() # Tickets abrufen, inklusive customer_ID cursor.execute(""" SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID FROM Kunden.tickets t JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID JOIN Kunden.services s ON s.service_ID = t.service_ID ORDER by t.createdate ASC """) tickets = cursor.fetchall() mydb.close() return tickets def fetch_customer_data(customer_id): # Verbindung zur Datenbank herstellen mydb = mysql.connector.connect( host=os.getenv("MYSQL_HOST"), user=os.getenv("MYSQL_USER"), password=os.getenv("MYSQL_PASSWORD"), database=os.getenv("MYSQL_DATABASE") ) cursor = mydb.cursor() # Kundendaten basierend auf customer_ID abrufen cursor.execute("""SELECT co.companyname, co.street,co.housenumber, co.postcode, co.city, c.customer FROM company co JOIN customers c ON c.customer_ID = co.customer_ID WHERE co.customer_id = %s""", (customer_id,)) customer_data = cursor.fetchone() mydb.close() return customer_data def fetch_customer_servicetime(customer_id): # Verbindung zur Datenbank herstellen mydb = mysql.connector.connect( host=os.getenv("MYSQL_HOST"), user=os.getenv("MYSQL_USER"), password=os.getenv("MYSQL_PASSWORD"), database=os.getenv("MYSQL_DATABASE") ) cursor = mydb.cursor() # Kundendaten basierend auf customer_ID abrufen cursor.execute("""SELECT servicetime FROM `tickets.customers.servicetime` WHERE customer_id = %s""", (customer_id,)) customer_servicetime = cursor.fetchone() mydb.close() return customer_servicetime def fetch_customer_price(price, customer_ID, service_ID): mydb = mysql.connector.connect( host=os.getenv("MYSQL_HOST"), user=os.getenv("MYSQL_USER"), password=os.getenv("MYSQL_PASSWORD"), database=os.getenv("MYSQL_DATABASE") ) cursor = mydb.cursor() # Prozentwert aus der Datenbank abrufen cursor.execute(f"""SELECT percent FROM `customers.pricechange` WHERE customer_ID = {customer_ID} and service_ID = {service_ID}""") customer_price_percent = cursor.fetchone() mydb.close() # Preis in Minuten umrechnen (da der aktuelle Preis in Stunden angegeben ist) price_per_minute = price / 60 # Umrechnung von Stunden auf Minuten # Falls ein Prozentwert existiert, diesen auf den Minutenpreis anwenden if customer_price_percent: price_per_minute += price_per_minute * (customer_price_percent[0] / 100) # print(f"Preis pro Minute nach Aufschlag von {customer_price_percent[0]}%: {price_per_minute:.2f} €") else: print(f"Standard Preis pro Minute: {price_per_minute:.2f} €") return price_per_minute def replace_text_in_run_with_format(run, key, value): if f"{{{key}}}" in run.text: run.text = run.text.replace(f"{{{key}}}", str(value)) run.font.name = 'Verdana' run.font.size = Pt(10) run.font.bold = False run.font.italic = False def insert_page_break(paragraph): run = paragraph.add_run() run.add_break(WD_BREAK.PAGE) def replace_text_in_paragraph(paragraph, key, value): for run in paragraph.runs: replace_text_in_run_with_format(run, key, value) def set_cell_border(cell, **kwargs): tc = cell._tc tcPr = tc.get_or_add_tcPr() borders = OxmlElement('w:tcBorders') for border_name in ["top", "left", "bottom", "right"]: border = kwargs.get(border_name, None) if border: element = OxmlElement(f"w:{border_name}") element.set(qn("w:val"), border.get("val", "single")) element.set(qn("w:sz"), border.get("sz", "4")) element.set(qn("w:space"), border.get("space", "0")) element.set(qn("w:color"), border.get("color", "000000")) borders.append(element) tcPr.append(borders) def fill_template(doc_path, output_path, data, tickets): doc = Document(doc_path) # Platzhalter in normalem Text ersetzen for paragraph in doc.paragraphs: for key, value in data.items(): if f"{{{key}}}" in paragraph.text: replace_text_in_paragraph(paragraph, key, value) if "{page_breaker}" in paragraph.text: if len(tickets) >= 7: paragraph.text = paragraph.text.replace("{page_breaker}", "") insert_page_break(paragraph) else: paragraph.text = paragraph.text.replace("{page_breaker}", "") # Platzhalter in der ersten Tabelle ersetzen first_table = doc.tables[0] for row in first_table.rows: for cell in row.cells: for paragraph in cell.paragraphs: for key, value in data.items(): replace_text_in_paragraph(paragraph, key, value) # Bearbeiten der zweiten Tabelle für Ticketdaten second_table = doc.tables[1] for ticket in tickets: row = second_table.add_row() row.cells[0].text = ticket[0] # Ticketnummer row.cells[1].text = ticket[1] # Tickettitel row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren row.cells[3].text = str(ticket[6]) # timerange (time_unit) # Formatierung und Ausrichtung für jede Zelle der neuen Zeile setzen for idx, cell in enumerate(row.cells): for paragraph in cell.paragraphs: if idx == 1: paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT else: paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER for run in paragraph.runs: run.font.name = 'Verdana' run.font.size = Pt(10) run.font.bold = False cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER set_cell_border(cell, top={"val": "single", "sz": "4", "color": "000000"}, bottom={"val": "single", "sz": "4", "color": "000000"}, left={"val": "single", "sz": "4", "color": "000000"}, right={"val": "single", "sz": "4", "color": "000000"}) # Berechnungen (z.B. Gesamtzeit, Preise) gesamt_time_unit = sum(int(ticket[6]) for ticket in tickets) data['gesamt_time_unit'] = gesamt_time_unit # Zeit größer als Servicetime if gesamt_time_unit >= customer_servicetime[0]: data['sl_time_unit'] = gesamt_time_unit + customer_servicetime[0] data['sl_minus_unit'] = gesamt_time_unit - customer_servicetime[0] data['time_unit_sum'] = gesamt_time_unit + data['zl_time_unit'] data['price_per_minute'] = customer_price data['price_ex_mwst'] = gesamt_time_unit * data['price_per_minute'] data['mwst_set'] = data['price_ex_mwst'] * 0.19 data['sum'] = data['price_ex_mwst'] + data['mwst_set'] data['price_ex_mwst'] = f"{data['price_ex_mwst']:.2f}".replace(".",",") data['mwst_set'] = f"{data['mwst_set']:.2f}".replace(".",",") data['sum'] = f"{data['sum']:.2f}".replace(".",",") # Platzhalter in der dritten Tabelle ersetzen third_table = doc.tables[2] for row in third_table.rows: for cell in row.cells: for paragraph in cell.paragraphs: for key, value in data.items(): if key == "sum": # Setze den Text und mache ihn fett for run in paragraph.runs: if f"{{{key}}}" in run.text: run.text = run.text.replace(f"{{{key}}}", str(value)) run.font.bold = True # Fett setzen else: replace_text_in_paragraph(paragraph, key, value) doc.save(output_path) # Hauptprogramm if __name__ == "__main__": tickets = fetch_tickets_from_database() service_ID = next(iter(set(ticket[8] for ticket in tickets))) price = next(iter(set(ticket[7] for ticket in tickets))) customer_ids = set(ticket[4] for ticket in tickets) for customer_id in customer_ids: customer_data = fetch_customer_data(customer_id) customer_servicetime = fetch_customer_servicetime(customer_id) customer_price = fetch_customer_price(price, customer_id, service_ID) customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id] if not customer_data: print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!") continue day = customer_tickets[0][5] now = datetime.now() if now.month == 1: last_month = 12 year = now.year - 1 else: last_month = now.month - 1 year = now.year startdate = datetime(year, last_month, day) enddate = startdate + relativedelta(months=1) - timedelta(days=1) data = { "name": customer_data[0], "street": customer_data[1], "housenumber": customer_data[2], "postcode": customer_data[3], "city": customer_data[4], "customernumber": customer_data[5], "year": datetime.now().year, "ordernumber": "0001", "startdate": startdate.strftime("%d.%m.%Y"), "enddate": enddate.strftime("%d.%m.%Y"), "today": datetime.now().strftime("%d.%m.%Y"), "price_per_minute": customer_price, "servicetime": customer_servicetime[0], "gesamt_time_unit": 0, "price_ex_mwst": 0, "sl_time_unit": 0, "sl_minus_unit": 0, "zl_time_unit": 0, "time_unit_sum": 0, "mwst_set": 0, "sum": 0, } output_path = f"apps/ticket_export/exports/RE2024.{customer_data[5]}.{data['ordernumber']}.docx" fill_template('apps/ticket_export/template.docx', output_path, data, customer_tickets) print("True")