import tkinter from PIL import Image import requests import webbrowser import customtkinter as ctk from tkinter import messagebox from tkinter import ttk from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas from datetime import datetime import datetime import check_api STATUS_PAID = "in_progress" keys = check_api.run() CLIENT_ID = keys[0] CLIENT_SECRET = keys[1] SHOPWARE_URL = keys[2] current_order_id = None def get_order_line_items(access_token, order_id): headers = { "sw-access-key": CLIENT_ID, "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } items_url = f"{SHOPWARE_URL}/api/order/{order_id}/line-items" response = requests.get(items_url, headers=headers) response.raise_for_status() return response.json()["data"] def get_order_customer(access_token, customer_id): headers = { "sw-access-key": CLIENT_ID, "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } customer_url = f"{SHOPWARE_URL}/api/order-customer/{customer_id}" response = requests.get(customer_url, headers=headers) response.raise_for_status() return response.json()["data"] def get_order_billing_address(access_token, order_id): headers = { "sw-access-key": CLIENT_ID, "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } address_url = f"{SHOPWARE_URL}/api/order/{order_id}/billing-address/" response = requests.get(address_url, headers=headers) response.raise_for_status() return response.json()["data"][0] def get_access_token(): token_url = f"{SHOPWARE_URL}/api/oauth/token" data = { "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET, "grant_type": "client_credentials" } response = requests.post(token_url, data=data) response.raise_for_status() return response.json()["access_token"] def get_paid_orders(access_token): headers = { "sw-access-key": CLIENT_ID, "authorization": f"Bearer {access_token}", "Content-Type": "application/json" } orders_url = f"{SHOPWARE_URL}/api/search/order" query = { "limit": 100, "page": 1, "filter": [{ "type": "equals", "field": "stateMachineState.technicalName", "value": STATUS_PAID }] } response = requests.post(orders_url, headers=headers, json=query) response.raise_for_status() return response.json()["data"] def get_order_details(access_token, order_id): headers = { "sw-access-key": CLIENT_ID, "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } items_url = f"{SHOPWARE_URL}/api/order/{order_id}/line-items" address_url = f"{SHOPWARE_URL}/api/order/{order_id}/billing-address/" response_items = requests.get(items_url, headers=headers) response_address = requests.get(address_url, headers=headers) response_items.raise_for_status() response_address.raise_for_status() return response_items.json()["data"], response_address.json()["data"][0] def show_order_details(event): global current_order_id selected_item = tree_orders.focus() if not selected_item: return values = tree_orders.item(selected_item, "values") order_number = values[0] customer_name = values[1] access_token = get_access_token() orders = get_paid_orders(access_token) selected_order = next((o for o in orders if o['attributes']['orderNumber'] == order_number), None) if selected_order: order_id = selected_order['id'] current_order_id = order_id product_line, billing_address = get_order_details(access_token, order_id) frame_orders.pack_forget() tree_details.delete(*tree_details.get_children()) for product in product_line: label = product['attributes'].get('label', 'Unbekanntes Produkt') quantity = product['attributes']['quantity'] price = product['attributes']['totalPrice'] tree_details.insert("", "end", values=(label, quantity, f"{price:.2f} €")) label_details.configure(text=f"Bestellung: {order_number} - {customer_name}") frame_details.pack(fill="both", expand=True) def back_to_orders(): frame_details.pack_forget() frame_orders.pack(fill="both", expand=True) def print_single_order(): if not current_order_id: messagebox.showerror("Fehler", "Keine Bestellung ausgewählt!") return access_token = get_access_token() orders = get_paid_orders(access_token) selected_order = next((o for o in orders if o['id'] == current_order_id), None) if selected_order: filename = generate_combined_pdf([selected_order], access_token) messagebox.showinfo("Erfolg", f"Lieferschein {filename} wurde erstellt!") else: messagebox.showerror("Fehler", "Bestellung nicht gefunden!") def generate_combined_pdf(orders, access_token): current_date = datetime.datetime.today().strftime("%d.%m.%Y") filename = f"Lieferschein_{current_date}.pdf" pdf = canvas.Canvas(filename, pagesize=A4) pdf.setTitle(f"Lieferschein {current_date}") pdf.setFont("Helvetica-Bold", 16) pdf.drawString(50, 800, "Sammel-Lieferschein") pdf.setFont("Helvetica", 12) pdf.drawString(50, 780, f"Erstellt am: {current_date}") y_position = 750 for order in orders: try: customer_id = order["relationships"]["orderCustomer"]["data"]["id"] customer = get_order_customer(access_token, customer_id) billing_address = get_order_billing_address(access_token, order["id"]) product_line = get_order_line_items(access_token, order["id"]) # Bestell-Header pdf.setFont("Helvetica-Bold", 12) pdf.drawString(50, y_position, f"Bestellnummer: {order['attributes']['orderNumber']}") date_obj = datetime.datetime.strptime(order['attributes']['orderDate'], "%Y-%m-%dT%H:%M:%S.%f%z") date_str = date_obj.strftime("%d.%m.%Y") pdf.setFont("Helvetica", 10) pdf.drawString(50, y_position - 20, f"Bestelldatum: {date_str}") # Rahmen um Lieferadresse pdf.setStrokeColorRGB(0, 0, 0) # Schwarz #pdf.rect(45, y_position - 110, 300, 80, stroke=1, fill=0) # Rechteck um Adresse # Lieferadresse pdf.setFont("Helvetica-Bold", 10) pdf.drawString(50, y_position - 100, "Lieferadresse:") pdf.setFont("Helvetica", 10) pdf.drawString(50, y_position - 120, f"{customer['attributes']['firstName']} {customer['attributes']['lastName']}") pdf.drawString(50, y_position - 140, f"{billing_address['attributes']['street']}") pdf.drawString(50, y_position - 160, f"{billing_address['attributes']['zipcode']} {billing_address['attributes']['city']}") y_position -= 180 # Platz nach Adresse # Produktliste for product in product_line: pdf.rect(50, y_position - 2, 10, 10, stroke=1, fill=0) # Checkbox für Abhaken label = product['attributes'].get('label', 'Unbekanntes Produkt') product_number = product['attributes']['payload'].get('productNumber', 'Keine Nummer') quantity = product['attributes']['quantity'] price = product['attributes']['totalPrice'] pdf.drawString(70, y_position, f"{label}") pdf.drawString(250, y_position, f"{product_number}") pdf.drawString(350, y_position, f"{quantity}") pdf.drawString(400, y_position, f"{price:.2f} €") y_position -= 20 # Falls die Seite voll ist, neue Seite beginnen if y_position < 100: pdf.showPage() y_position = 800 y_position -= 40 # Platz nach jeder Bestellung except Exception as e: print(f"Fehler beim Erstellen des Lieferscheins für Bestellung {order['attributes']['orderNumber']}: {str(e)}") pdf.save() print(f"Lieferschein gespeichert: {filename}") return filename def print_all_orders(): access_token = get_access_token() orders = get_paid_orders(access_token) if not orders: messagebox.showinfo("Info", "Keine Bestellungen gefunden.") return filename = generate_combined_pdf(orders, access_token) messagebox.showinfo("Erfolg", f"Gesammelter Lieferschein {filename} wurde erstellt!") def update_table(): access_token = get_access_token() orders = get_paid_orders(access_token) # Tabelle leeren for row in tree_orders.get_children(): tree_orders.delete(row) for order in orders: order_number = order['attributes']['orderNumber'] _, billing_address = get_order_details(access_token, order['id']) tree_orders.insert("", "end", values=( order_number, f"{billing_address['attributes']['firstName']} {billing_address['attributes']['lastName']}", billing_address['attributes']['street'], f"{billing_address['attributes']['zipcode']} {billing_address['attributes']['city']}" )) def open_link(event=None): webbrowser.open("https://itdata-gera.de") def execute_with_error_handling(func, *args, **kwargs): try: func(*args, **kwargs) # Die gewünschte Funktion ausführen except Exception as e: root.after(0, show_error_message, str(e)) # Fehler in GUI anzeigen # GUI-Fehlermeldung anzeigen def show_error_message(error_text): tkinter.messagebox.showerror("Fehler", f"Ein Fehler ist aufgetreten:\n{error_text}") # GUI-Erstellung root = ctk.CTk() root.title("Lieferschein-Drucker") root.resizable(False, False) window_width = 900 window_height = 500 # Bildschirmgröße abrufen screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() # Position berechnen (Mitte des Bildschirms) x_position = (screen_width // 2) - (window_width // 2) y_position = (screen_height // 2) - (window_height // 2) # Fenstergröße & Position setzen root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}") # **Bestellübersicht** frame_orders = ctk.CTkFrame(root) button_all_print = ctk.CTkButton(frame_orders, text="API ändern", command=lambda: execute_with_error_handling(check_api.rerun),fg_color="#2b2b2b",text_color="white",anchor=tkinter.RIGHT) button_all_print.pack(pady=5,anchor="ne") label_orders = ctk.CTkLabel(frame_orders, text=f"Bezahlte Bestellungen - {datetime.datetime.now().strftime("%d.%m.%Y")}", font=("Helvetica", 15)) label_orders.pack(pady=5) columns_orders = ("Bestellnummer", "Kunde", "Straße", "PLZ/Stadt") tree_orders = ttk.Treeview(frame_orders, columns=columns_orders, show="headings", cursor="hand2") for col in columns_orders: tree_orders.heading(col, text=col) tree_orders.column(col, width=150) tree_orders.pack(expand=True, fill="both") tree_orders.bind("<>", show_order_details) button_update = ctk.CTkButton(frame_orders, text="Bestellungen laden", command=lambda: execute_with_error_handling(update_table), fg_color="lightblue",text_color="black",anchor=tkinter.RIGHT) button_update.pack(side="left",pady=5,padx=10) logo = ctk.CTkImage(dark_image=Image.open('logo.png'),size=(130,30)) logo_label = ctk.CTkLabel(root, text="", image=logo, fg_color="#2b2b2b",cursor="hand2") logo_label.bind("", open_link) logo_label.place(relx=0.5, rely=1.0, anchor="s",y=-15) button_all_print = ctk.CTkButton(frame_orders, text="Gesammelten Lieferschein drucken", command=lambda: execute_with_error_handling(print_all_orders),fg_color="orange",text_color="black") button_all_print.pack(side="right",pady=15, padx=10) frame_orders.pack(fill="both", expand=True) # **Detailansicht** frame_details = ctk.CTkFrame(root) label_details = ctk.CTkLabel(frame_details, text="", font=("Helvetica", 12)) label_details.pack(pady=5) columns_details = ("Produkt", "Anzahl", "Preis") tree_details = ttk.Treeview(frame_details, columns=columns_details, show="headings") for col in columns_details: tree_details.heading(col, text=col) tree_details.pack(expand=True, fill="both") button_back = ctk.CTkButton(frame_details, text="Zurück", command=back_to_orders) button_back.pack(side="left", padx=20, pady=15) logo_label_1 = ctk.CTkLabel(root, text="", image=logo, fg_color="#2b2b2b",cursor="hand2") logo_label_1.bind("", open_link) logo_label_1.place(relx=0.5, rely=1.0, anchor="s",y=-15) button_print = ctk.CTkButton(frame_details, text="Diese Bestellung drucken", command=print_single_order, fg_color="lightgreen", text_color="black") button_print.pack(side="right", padx=20,pady=15) # Error Handling für Timeout root.after(100, lambda: execute_with_error_handling(update_table)) root.mainloop()