Lieferschein_Drucker/main.py

343 lines
13 KiB
Python

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("<<TreeviewSelect>>", 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("<Button-1>", 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("<Button-1>", 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()