Logistik ist ein komplexes Thema, und selbst wenn man die Auslieferung der Ware einem Spediteur überträgt, so kann man als Verkäufer sich nicht vollständig davon befreien. Denn der Spediteur, eingeschränkt durch seine Fahrzeuge, Ressourcen, Depotstandorten und Möglichkeiten, wird nicht jede Sendung akzeptieren. Als Verkäufer ist es daher wichtig, zu wissen, ob eine Sendung mit einem bestimmten Frachtführer versendet werden kann oder nicht. Dies im Odoo automatisieren zu können, spart dabei deutlich Zeit, und erlaubt es oft, schon beim Erstellen eines Verkaufsauftrages den Spediteur und damit die Lieferkosten festzulegen.
Problemstellung: Die Vielzahl von Anforderungen
Der Odoo-Standard selbst liefert dort eine sehr eingeschränkte Funktionalität, welche eine Filterung nach Lieferort erlaubt. Angesichts der Möglichkeiten, die als Anforderungen von den Spediteuren kommen, oder die man aus Erfahrung selbst als Verkäufer gemacht hat, ist dies jedoch nicht ausreichend. Denn selbst die wohl häufigste Einschränkung, nach Gewicht und Dimensionen, wird vom System nicht abgedeckt. Nachdem wir von mehreren Kunden darum gebeten wurden, haben wir die daraus gelernten Lektionen genutzt, um eine allgemeine, modular aufgebaute Lösung zur Frachtführereinschränkung zu entwickeln.
Lösungskonzeption: Entwicklung einer vollumfänglichen und dynamischen Lösung
Dabei haben wir drei Design-Prinzipien verfolgt, um eine möglichst weit anwendbare Lösung zu erhalten. Das erste Prinzip war Modularität: Es sollte so einfach wie möglich sein, eine Einschränkung im System hinzuzufügen, oder wieder zu entfernen, und es sollte mit möglichst wenig Aufwand möglich sein, spezielle Kundenanforderungen als neues Modul hinzuzufügen, ohne den Code des Basis-Moduls anpassen zu müssen. Das zweite Prinzip war Flexibilität: Da nicht vorhergesagt werden kann, was für Anforderungen ein Spediteur stellt, dürfen den Sub-Modulen so wenig Einschränkungen wie möglich darüber gegeben werden, was für Daten sie verwenden können. Das dritte Prinzip war Effizienz: Aus Erfahrungswerten hatten wir bereits festgestellt, dass eine einfache Erweiterung des Basis-Codes für komplizierte Anforderungen zu viel Rechenzeit benötigt, da bestimmte Funktionen viel zu oft aufgerufen werden.
Zusätzlich haben wir aus Erfahrung noch ein weiteres Feature definiert, was im Odoo leider noch gar nicht vorhanden war: Die Möglichkeit, auch an der Lieferung die Frachtführereinschränkungen mit einzubeziehen. Ohne diese Möglichkeit gibt es eine wichtige Klasse an Einschränkungen, die man nicht korrekt umsetzen könnte: Verpackungsdimensionen. Während man aus den Maßen einzelner Waren ungefähr ein Verpackungsmaß errechnen könnte, steht der endgültige Wert erst fest, wenn alles auf der Palette verladen und verpackt ist. Daher ist es wichtig, zu diesem Zeitpunkt noch einmal einsehen zu können, ob die Lieferung mit diesem Spediteur auch herausgehen kann.
Basierend auf diesen Anforderungen erstellten wir zwei Basismodule, welche für die Verwaltung der Frachtführereinschränkungen zuständig sind. Das erste ist der Manager, welcher dazu dient, alle Einschränkungen anzuwenden. Er hat eine Funktion, bei der ein Submodul eine Einschränkungsfunktion registriert. Wenn die Funktionen angewendet werden, geht der Manager seine Liste an Funktionen durch, lässt sich von allen die notwendigen Bedingungen zurückgeben, und wendet dann diesen Satz an Bedingungen auf die Liste aller Frachtführer im Odoo an. Das zweite Modul setzt die Frachtführer-Einschränkung an der Lieferung um, indem es an der Lieferung die notwendigen Felder und Funktionen hinzufügt, um die Frachtführer kontrollieren zu können. Allerdings setzt das Manager-Modul bereits viele Funktionen um, die notwendig sind, um die Lieferungen einzubinden, selbst wenn das Lieferungs-Modul nicht installiert ist. Das erfordert Modularität, damit die einzelnen Sub-Module bei ihrer Filterung nicht noch aufpassen müssen, ob das Liefer-Modul mit installiert ist.
Für die Flexibilität wird den Sub-Modulen die ganze Bandbreite an Daten gegeben: Deine registrierten Filter-Funktionen erhalten als Eingabe die kompletten Datensätze des Verkaufsauftrages und der Lieferung, falls vorhanden. Damit können sie auf praktisch alle im Odoo über den Verkaufsprozess hinterlegten Daten zugreifen, indem sie entsprechende Felder und Untermodelle dieser Datensätze anzapfen. Dies ist im Kontrast zum Odoo-Standard zu sehen, wo die Funktion zum Bestimmen, ob eine Versandmethode zulässig ist, nur einen einzelnen Parameter enthält, nämlich die Lieferadresse. Aus dieser lässt sich nicht mehr zurückverfolgen, welcher Auftrag oder welche Lieferung, und daraus welche Produkte und Verpackungen mit betrachtet werden müssen.
Um die Effizienz zu erhöhen, wurde so gut wie es geht die Anzahl der Funktionsaufrufe und Datenbankabfragen minimiert. Der grundlegende Baustein an der Stelle ist, dass die registrierten Filter-Funktionen als eine Bedingung an den Frachtführer zurückgeben müssen. Anstelle jeden Frachtführer zu fragen "Passt dieser Verkauf auf deine Anforderungen", und jedes mal die Eckdaten des Verkaufes neu zu berechnen (wie z.B. ob die PLZ passt), werden aus den Eckdaten Anforderungen an den Frachtführer bestimmt. Es wird also nicht gefragt "Passt dieses 6 kg Paket zu dir?", wobei jedes Mal neu berechnet wird, dass das Paket 6 kg schwer ist. Stattdessen wird gefragt: "Welcher Frachtführer hat ein Gewichtslimit oberhalb von 6 kg?" mit nur einmaliger Berechnung des Gewichtes. Durch diese Änderung in der Abfrage-Methode werden nicht nur die Berechnungen reduziert, es erlaubt auch, die Filterung innerhalb der Odoo-Hierarchie zu verschieben: Anstelle eine langsame Schleife in Python zu machen, erfolgt die Abfrage der Bedingungen auf der Datenbank als SQL-Befehl, und damit deutlich schneller.
Praxisbeispiel: Ausgrenzung eines Lieferortes
Wie ein Sub-Modul aufgebaut ist und was es alles leisten kann, stellen wir am Beispiel des Lieferortes einmal vor. Bei der Einschränkung des Lieferortes gibt es zwei Herausforderungen: Zum einen die Darstellung von Liefergebieten, und zum anderen das Einlesen von Postleitzahlen. Für beides hat der Odoo-Standard bereits seine Lösungen, aber auch Grenzen.
In den Odoo-Versionen 16 und 17 erlaubt es Odoo, das Liefergebiet eines Frachtführers mittels drei Listen zu bestimmen: Einer Liste zugelassener Länder, einer Liste zugelassener Bundesländer, und einer List an zugelassenen Postleitzahl-Präfixen. Die Postleitzahl-Präfixe ersetzen ein Postleitzahl-Intervall aus den vorherigen Odoo-Versionen (also z.B 14 oder 15), bei dem man eine maximale und minimale Postleitzahl als Werte angibt, und an alle Zahlen dazwischen geliefert werden kann. Eine Adresse muss auf alle drei Bedingungen passen, um zugelassen zu werden - ist also z.B. als Länder Kanada und die Vereinigten Staaten gesetzt, und als Bundesländer bloß Kalifornien, werden Adressen in Kanada abgelehnt, weil sie nicht in Kalifornien sind.
Ein sicher sehr verständliches Liefergebiet, welches ein deutscher Spediteur nennen könnte, ist "Ganz Deutschland außer Helgoland", da für den Transport auf die Insel ja ein Schiff und nicht nur der Lastwagen benötigt wird. Wenn man versucht, dieses in Odoo darzustellen, kommt man mit dem Intervall von Odoo 15 nicht dorthin: Man kann entweder das Intervall "00000 bis 27497" oder das Intervall "27499 bis 99999" angeben, aber nicht beides. Mit Odoo 16 kann man es darstellen, müsste aber bis zu 44 Präfixe definieren, um eine spezifische Postleitzahl auszuschließen. Und egal welche Version man verwendet, wird es unbrauchbar, sobald noch mehr Länder dazukommen. "Deutschland, Österreich und Polen, außer Helgoland" lässt sich nicht darstellen: Wenn eine Postleitzahl ausgeschlossen wird, wird sie für alle Länder ausgeschlossen.
Um dort eine allgemeine Lösung umzusetzen, haben wir die Länderauswahl von drei Listen von unabhängigen Bedingungen zu einer einzelnen Liste von je drei zusammenhängenden Bedingungen umgebaut: Jede Zeile hat ein Land, ein Bundesland und ein PLZ-Intervall, und eine Adresse wird zugelassen, wenn es eine Zeile gibt, die darauf passt. Damit lassen sich unsere obigen Problemfälle gut abdecken: In der Zeile für Kanada lässt sich Kalifornien nicht als Bundesland auswählen, kann also nicht zu dem obigen weniger intuitiven Verhalten führen - die beiden Teile der Bedingung, "Kanada" und "US nur Kalifornien" sind zwei getrennte Zeilen. Genauso lässt sich "Deutschland, Österreich und Polen, außer Helgoland" als vier Zeilen klar darstellen: Eine Zeile für Deutschland mit dem PLZ-Intervall "00000 bis 27497", eine zweite für Deutschland mit den PLZ-Intervall "27499 bis 99999", eine dritte für Österreich und eine vierte für Polen.
Die Entscheidung, das Intervall anstelle der Präfixe zu verwenden, liegt an der zweiten Herausforderung: Deutsche Postleitzahlen können eine führende Null enthalten. Viele Programme sind jedoch darauf nicht angepasst, und speichern die Postleitzahl daher als Ganzzahl. Wenn ein solches Programm mit Odoo kommuniziert, kann es schnell passieren, dass die an einer Adresse gespeicherte Postleitzahl zu kurz ist, also z.B. nur "1099" anstelle von "01099". Odoo speichert die Postleitzahl als Zeichenkette, so dass es selbst die 0 nicht vergessen kann, hat aber keine Prüfung, dass es andere Programme nicht tun.
Wenn man mit Präfixen arbeitet, führt so eine fehlende Null zu schwerer behebbaren Problemen: Wenn der Filter die Präfixe "10", "12" und "13" sind, ist es nicht sofort ersichtlich, dass "1099" nicht darunter fallen sollte, denn aus den Präfixen kann man die erwartete Länge der Zahl nicht ablesen. Das Intervall "10000 bis 10999" mit "1099" zu vergleichen, erlaubt schneller zu erkennen, dass hier eine führende Null fehlt. Bevor man die PLZ mit den Intervallgrenzen vergleicht, kann man die fehlende 0 noch anhängen, und kommt so zum korrekten Ergebnis: Der PLZ-Bereich für Berlin beinhaltet nicht Dresden.
Eine solche Liste an Postleitzahl-Gebieten zeigt auch schnell die Notwendigkeit der Effizienz: Wenn man dort das Datenmodell jedes Frachtführers einzeln anspricht, um anzufragen, ob dieser eine Zeile hat, sind dies relativ viele Befehle, denn der Frachtführer muss zuerst seine Zeilen suchen, dann über jede einzeln darüber gehen, und die Werte mit denen der Adresse abgleichen. Kommt dort noch die aufwändige Operation hinzu, die Postleitzahl-Längen aufeinander abzustimmen, braucht eine solche Abfrage viel zu lange. Dort andersherum heranzugehen ist schneller: Man fragt ab, welche aus der Gesamtheit aller Zeilen von allen Frachtführern auf unsere Bedingungen passen und bestimmt dann von diesen, welche Frachtführer die Bedingung erfüllen. Diese Liste an passenden Frachtführern wird dann als Bedingung an den Manager zurückgegeben, so dass der Aufwand für die Kombination mit den anderen Bedingungen sehr gering ist.
Bei anderen Einschränkungen, wie Gewicht und Abmaße, sind die Bedingungen deutlich einfacher darzustellen, da es dort nur ein Intervall gibt - ein Frachtführer wird ein Mindest- und Höchstgewicht haben, aber keine Ausnahmen in der Mitte. Daher können diese Werte einfach am Frachtführer hinterlegt werden, und man fragt wie oben erwähnt einfach ab, ob das Mindestgewicht unter und das Höchstgewicht über dem berechneten Gewicht der Lieferung liegt.
Interessanter ist bei diesen Größen das Zusammenspiel mit dem Verpackungsprozess, denn durch das Anordnen auf Paletten oder in Kartons können sich die Abmaße oder das Gewicht ändern. Damit kann ein Frachtführer, der basierend auf den reinen Produktmaßen zulässig war, plötzlich nicht mehr zulässig sein. Wurde bereits ein Frachtführer für die Lieferung ausgewählt, sollte dies in den Prozess des Kunden eingebaut werden. Für einen Kunden haben wir implementiert, dass er in diesem Fall den Frachtführer neu auswählt, indem er es zufällig aus der Liste der noch Zugelassenen wählt. Aber genauso leicht zu implementieren wäre eine Warnmeldung oder das Setzen einer Aktivität an der Lieferung, wenn ein solcher Fall auftritt.
Während die Änderung der Zulässigkeit während des Verpackens über die Standard-Odoo-Engine ablaufen kann, da ja jeder Lieferprozess einzeln abgehandelt wird, gibt es an einer anderen Quelle eine Änderung, die spezielle Aufmerksamkeit benötigt: Wenn man am Frachtführer die Parameter ändert, kann das genauso einen Einfluss auf die Zulässigkeit haben. Wenn wir Polen beispielsweise aus der Liste der Länder streichen, müssen alle Sendungen nach Polen, die diesen Frachtführer verwenden wollen, als nicht mehr zulässig erkannt und behandelt werden. Dort jedoch den Standard-Auslöser zu verwenden, dass wir bei einer Änderung alle abhängigen Felder neu berechnen, bringt jedes reale System an die Grenzen: Denn bei jeder Eingabe in das Frachtführer-Formular tausende von Sendungen durchzugehen, führt zu extremen Rechen- und damit Ladezeiten. Daher, um die Oberfläche für den Kunden nutzbar zu halten, wird eine solche Berechnung separat durchgeführt. Mittels einer automatischen Aktion, die jede Nacht prüft, ob sich an einem Frachtführer etwas verändert hat, wird der Neuberechnungsprozess zu einer Zeit angestoßen, in der keine Nutzer auf dem System sind. Zusätzlich ermöglicht der selbst geschriebene Code der automatischen Aktion, dass wir die zu berechnenden Lieferungen auf ein Minimum reduzieren. Nur Lieferungen, die im Moment ausstehen, brauchen eine Anpassung im Frachtführer, und vorrangig nur solche, bei denen der verwendete Frachtführer sich verändert hat. Diese Vorfilterung reduziert die Rechenzeit auf ein Minimum, ohne die Funktionalität zu beeinflussen.
Fazit
Mit der Erweiterung für die Frachtführereinschränkung in Odoo wird eine detaillierte Filterung der Frachtführer basierend auf Kriterien wie Gewicht, Abmessungen und Lieferort direkt in Odoo ermöglicht. Durch die Umgestaltung des Lieferortfilters und die Verwendung von mehreren getrennten Bedingungen wird eine präzisere und effizientere Steuerung erreicht. Die Erweiterung berücksichtigt auch die Dynamik während des Verpackungsprozesses und bietet Lösungen für Änderungen an den Frachtführerparametern, wodurch sich das Modul auf eure spezifischen Anforderungen anpassen lässt.
Ihr stoßt ebenfalls mit euren Anforderungen oder den eurer Spediteure an die Grenzen des Odoo-Standards oder habt generelles Interesse an der Abbildung eurer Auslieferung in Odoo? Dann kontaktiert uns gern!
Quellen: odoo.com
Frachtführereinschränkungen in Odoo