#!/usr/bin/env python3 # Excel_Bruecke.py """ Kapitel Einfuehrung: Vom Excel-Solver zu Python - dieselbe Rechnung, dieselbe Datei. Das Programm bildet den vollstaendigen Arbeitsweg ab, den ein Excel-Modell im Betrieb sonst von Hand geht: Tabellenblatt lesen -> Modell bauen -> loesen -> Ergebnis zurueckschreiben Damit es ohne Vorbereitung laeuft, legt es die Eingabedatei beim ersten Start selbst an. Ersetzen Sie sie durch Ihre eigene Datei - solange die Spalten gleich heissen, aendert sich am Code nichts. Die vier Arbeitsschritte kommen aus or_kern.py (Kapitel Praxisfallen). Was hier steht, ist nur noch das, was diesen Fall ausmacht - der Rest ist gemeinsamer Unterbau. Wer das Modul nicht kennt: Es ist im Buch vollstaendig abgedruckt und liegt im selben Verzeichnis. Erzeugte Dateien (im Arbeitsverzeichnis): produktionsmix.xlsx Eingabe: Blaetter 'Produkte' und 'Kapazitaeten' produktionsmix_ergebnis.xlsx Ausgabe: Blaetter 'Plan' und 'Kennzahlen' Benoetigt: pandas, openpyxl, ortools, pydantic (ueber or_kern) """ from __future__ import annotations import os import pandas as pd from or_kern import (lade_produktionsproblem, loese_mit_glop, pruefe_loesung, schreibe_ergebnis) EINGABE = "produktionsmix.xlsx" AUSGABE = "produktionsmix_ergebnis.xlsx" def lege_beispieldatei_an(pfad: str) -> None: """Schreibt die Eingabemappe, wie sie auch aus dem Controlling kaeme.""" produkte = pd.DataFrame({ "Produkt": ["Tisch", "Stuhl", "Regal"], "Deckungsbeitrag": [240.0, 60.0, 130.0], "Montagestunden": [3.0, 1.0, 2.0], "Plattenmaterial": [6.0, 1.0, 4.0], }) kapazitaeten = pd.DataFrame({ "Ressource": ["Montagestunden", "Plattenmaterial"], "Verfuegbar": [150.0, 240.0], }) with pd.ExcelWriter(pfad, engine="openpyxl") as mappe: produkte.to_excel(mappe, sheet_name="Produkte", index=False) kapazitaeten.to_excel(mappe, sheet_name="Kapazitaeten", index=False) if __name__ == "__main__": if not os.path.exists(EINGABE): lege_beispieldatei_an(EINGABE) print(f"Beispiel-Eingabedatei angelegt: {EINGABE}") # 1. Lesen und pruefen. Faellt hier etwas auf, ist der Fehler noch # zuzuordnen - spaeter waere er nur noch eine merkwuerdige Zahl. problem = lade_produktionsproblem(EINGABE) # 2. Loesen. Einzige solverabhaengige Zeile des ganzen Programms - # 'loese_mit_scipy' waere ein Einzeiler-Wechsel. loesung = loese_mit_glop(problem) # 3. Abnahmepruefung gegen die Anforderungen, ohne den Solver zu fragen. beanstandungen = pruefe_loesung(problem, loesung) if beanstandungen: raise SystemExit("Abnahmepruefung fehlgeschlagen:\n - " + "\n - ".join(beanstandungen)) # 4. Zurueckschreiben - im Format, das die Fachabteilung ohnehin benutzt. schreibe_ergebnis(AUSGABE, problem, loesung) print("=" * 66) print(" PRODUKTIONSPLAN AUS DER EXCEL-MAPPE") print("=" * 66) for produkt in problem.produkte: menge = loesung.werte[produkt.name] print(f"{produkt.name:<18} {menge:8.1f} Stueck " f"{menge * produkt.deckungsbeitrag:12,.2f} EUR") print("-" * 66) print(loesung.als_bericht()) print("Abnahmepruefung: bestanden\n") # Die Schattenpreise beantworten die Frage, die der Plan nicht stellt: # Was waere eine zusaetzliche Einheit dieser Ressource wert? for ressource, preis in loesung.schattenpreise.items(): print(f" eine Einheit {ressource:<18} mehr waere wert: {preis:7.2f} EUR") print("=" * 66) print(f"Ergebnis geschrieben nach: {AUSGABE}")