[ADD] baker_recipe_wizard: Stufen sind Datensätze mit einer Beziehung #5

Open
odoo wants to merge 52 commits from odoo/19.0-recipe_wizard_stages into 19.0 AGit
Owner

Bisher trug die Reihenfolge die Struktur: die letzte Stufe war der Teig, alles
davor eine Vorstufe davon. Das kann nur zwei Ebenen ausdrücken -- ein
Anstellgut landete zwangsläufig neben dem Sauerteig statt darin.

Jetzt sagt eine Stufe, in welche Stufe sie geht. Dass eine Vorstufe nicht in
mehreren weiterführenden Stufen genutzt werden kann, ist damit keine Regel,
die man prüfen müsste, sondern eine Form, die sich nicht hinschreiben lässt:
die Beziehung ist ein einzelner Verweis.

Welche Stufe der Teig ist, wird ebenfalls gesagt statt geraten. Wer aus der
Reihenfolge schließt, hat beim zweiten wurzellosen Datensatz schon verloren --
und genau der ist der interessante Fall: eine Vorstufe, die niemand
angeschlossen hat. Nichts davon käme im Rezept an, deshalb warnt das Blatt,
solange es geschrieben wird, statt es beim Anwenden stillschweigend fallen zu
lassen.

Das Anwenden folgt der Beziehung und baut jede Stufe rekursiv: ein Codepfad
für jede Tiefe. Der Test dazu baut Anstellgut -> Sauerteig -> Teig; lässt man
die Mehlmenge der Unterstufen weg, meldet er 35 statt 40 %.

Die Sauerteig-Markierung wandert von der Zeile an die Stufe, wo sie
hingehört -- an der Zeile steht sie nur noch zur Anzeige.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

Bisher trug die Reihenfolge die Struktur: die letzte Stufe war der Teig, alles davor eine Vorstufe davon. Das kann nur zwei Ebenen ausdrücken -- ein Anstellgut landete zwangsläufig neben dem Sauerteig statt darin. Jetzt sagt eine Stufe, in welche Stufe sie geht. Dass eine Vorstufe nicht in mehreren weiterführenden Stufen genutzt werden kann, ist damit keine Regel, die man prüfen müsste, sondern eine Form, die sich nicht hinschreiben lässt: die Beziehung ist ein einzelner Verweis. Welche Stufe der Teig ist, wird ebenfalls gesagt statt geraten. Wer aus der Reihenfolge schließt, hat beim zweiten wurzellosen Datensatz schon verloren -- und genau der ist der interessante Fall: eine Vorstufe, die niemand angeschlossen hat. Nichts davon käme im Rezept an, deshalb warnt das Blatt, solange es geschrieben wird, statt es beim Anwenden stillschweigend fallen zu lassen. Das Anwenden folgt der Beziehung und baut jede Stufe rekursiv: ein Codepfad für jede Tiefe. Der Test dazu baut Anstellgut -> Sauerteig -> Teig; lässt man die Mehlmenge der Unterstufen weg, meldet er 35 statt 40 %. Die Sauerteig-Markierung wandert von der Zeile an die Stufe, wo sie hingehört -- an der Zeile steht sie nur noch zur Anzeige. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
odoo added 24 commits 2026-09-22 19:56:13 +00:00
Beide Editoren -- der Baum und das Formelblatt -- bauen auf derselben
Modellschicht auf. Solange sie in einem Modul mit einem der beiden steckte, war
der andere von ihm abhängig, obwohl er nichts davon benutzt.

Hier liegt, was beiden gehört: Rollen am Produkt, Bäckerprozente, die
Rekursion über die Stufen, die drei Teigausbeuten, der Backschritt, die Sperre
geteilter Vorstufen samt Öffnen und Ableiten, dazu Ansichten, Demodaten und
Übersetzung.

Der Name ändert sich mit: aus baker_recipe_editor wird baker_recipe, weil das
Modul keinen Editor mehr enthält. Die beiden Editoren werden eigene Module und
hängen hieran.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Änderungswünsche.

Gesamtmehl, Gesamtsalz und "verwendet in" verschwinden aus dem Formular; Salz
in Prozent und die drei Teigausbeuten bleiben. Das Zählfeld geht ganz: es war
reine Anzeige und hätte ohne Formular keinen Abnehmer mehr. Die Methode
dahinter bleibt, die trägt die Sperre.

Der Ableiten-Knopf hing bisher an jeder Vorstufenzeile. Wird eine Vorstufe nur
einmal verwendet, gibt es nichts abzuleiten -- sie gehört bereits zu diesem
einen Rezept, und eine Änderung daran kann kein anderes erreichen.

Die Ausnahme deckt einen Fall ab, den es vorher gar nicht gab: eine
Zubereitung, die MIT DEM MODUL kommt. Die liess sich bisher bearbeiten, und
die nächste Modulaktualisierung hätte die Änderung stillschweigend
überschrieben -- dieselbe Sorte unsichtbarer Verlust wie bei der geteilten
Vorstufe, nur mit der Zeit statt mit einem fremden Rezept als Gegner. Solche
Zubereitungen sind jetzt gesperrt, und genau deshalb muss der Ableiten-Knopf
dort auch dann erscheinen, wenn sie erst einmal verwendet wird. Erkannt werden
sie am externen Bezeichner: stammt er aus einem Modul, ist es ein Preset.

"Gesperrt" heisst damit zweierlei -- mehrfach verwendet oder aus dem Modul --
und beides hat dieselbe Antwort: leite dir eine eigene Kopie ab.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
44 Terme, über "odoo-bin i18n export" erzeugt und dann gefüllt. Enthält nur
noch, was zur Grundlage gehört -- die Texte der beiden Editoren liegen bei
ihnen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Rollen sind jetzt Mehl, Flüssigkeit und Salz. Wasser ist keine eigene
Rolle mehr, sondern eine Flüssigkeit mit 100 % Wasseranteil -- Milch eine mit
ihrem eigenen.

Das ist nicht nur eine Umbenennung, es macht die theoretische Teigausbeute
erst richtig. Sie zählt die SCHÜTTFLÜSSIGKEIT, und 2000 g Milch sind 2000 g
Schüttflüssigkeit, auch wenn davon nur 1740 g Wasser sind. Vorher zählte nur,
was die Rolle "water" trug, und Milch fiel ganz heraus. Der Unterschied
zwischen theoretischer und tatsächlicher TA ist damit genau das, wofür die
beiden Zahlen da sind.

Nebenbei verschwindet ein Sonderfall: die Feuchte je Einheit brauchte bisher
einen eigenen Zweig für Wasser. Jetzt trägt jede Zutat den Anteil bei, den sie
angibt, und eine Zubereitung das, was ihre Zeilen ergeben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fünf Mehle, Wasser, Milch und Salz als Rohstoffe, dazu fünf fertige
Zubereitungen: Roggensauerteig aus Vollkorn und aus 1150er, Weizensauerteig
aus Vollkorn, Levain liquide und Levito madre. Die Teigausbeute steht im
Namen, weil ein Bäcker danach greift -- TA 200 sind gleiche Teile Mehl und
Wasser, TA 150 die feste Führung.

Der Wasseranteil von Milch ist mit 87,5 angesetzt und aus der Zusammensetzung
gerechnet statt aus einer Nährwerttabelle abgeschrieben: 3,3 g Eiweiss,
4,8 g Kohlenhydrate, 3,5 g Fett und rund 0,7 g Mineralstoffe je 100 g ergeben
12,3 g Trockenmasse.

Die Demodaten führen ihre Mehle und ihr Wasser nicht mehr doppelt, sondern
greifen auf die Presets zu. Übrig bleibt dort, was den beiden Broten eigen
ist: Alpenroggenmehl, Tipo 0, Altbrot, Schabzigerklee.

Dabei ist ein Fehler im Preset-Schutz aufgefallen, der sich erst beim
tatsächlichen Laden zeigt: Er sperrte das MODUL aus seinen eigenen Daten aus.
Eine Aktualisierung schreibt die Presets neu, und der Wächter verbot es -- die
Datei liess sich kein zweites Mal laden. Die Sperre soll einen Menschen daran
hindern, etwas zu bearbeiten, das die nächste Aktualisierung überschreibt;
sie darf nicht die Aktualisierung selbst verhindern. Sie greift jetzt nicht,
solange Odoo Moduldaten lädt.

Nachgemessen an einer frisch aufgesetzten Datenbank: die fünf Presets kommen
mit genau der Teigausbeute heraus, die ihr Name nennt, sind gesperrt und als
Preset erkannt; die Demorezepte treffen weiterhin ihre Zahlen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Roggen-Anstellgut der Demodaten war Zeile für Zeile das Preset
"Rye sourdough 1150, DY 200" -- dieselben zwei Zutaten im selben Verhältnis.
Eine zweite Kopie davon zu führen ist genau die Doppelung, die dieses Modul
vermeiden soll. Die beiden Rezepte greifen jetzt darauf zu.

Das hat einen angenehmen Nebeneffekt: das Preset wird damit von zwei
Rezepturen verwendet und ist dadurch gesperrt. Die Demodaten zeigen den
Ableiten-Knopf also an echten Daten, ohne dass man dafür etwas konstruieren
müsste.

Das Weizen-Anstellgut bleibt Demodatum. 1050er Weizen bei TA 200 hat kein
Preset -- die gelieferten Weizenzubereitungen sind Vollkorn und 550er -- und
eines zu erfinden hiesse, die Preset-Liste stillschweigend zu erweitern.

Nachgemessen: die Rezepte treffen weiterhin ihre Zahlen, Neudorfer 169,58
gegen die angegebenen 170.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Presets tragen jetzt noupdate. Damit legt das Modul sie einmal an und
fasst sie nie wieder an -- eine Änderung daran überlebt also die
Aktualisierung, und das Schreibverbot, das sie schützen sollte, ist überflüssig
geworden. Es fällt weg, und mit ihm die Ausnahme, die ich einbauen musste,
damit das Modul überhaupt noch seine eigenen Daten laden konnte. Ein zweites
Laden geht ohne sie durch; die Ausnahme hing wirklich nur an dieser Sperre.

Gesperrt ist damit nur noch, was tatsächlich mehrfach verwendet wird. In den
Demodaten trifft das genau das eine Preset, das beide Rezepte als Anstellgut
nehmen -- die übrigen vier sind frei editierbar.

Neu ist der Löschschutz: die Stückliste einer verwendeten Zubereitung lässt
sich nicht mehr löschen. Das ist kein Komfort, sondern schliesst eine Lücke.
Löschen wäre kein Löschen: das Produkt bleibt als Zeile in jedem Rezept
stehen, das es verwendet, verliert aber seine Rezeptur -- damit ist es keine
Zubereitung mehr, sein Mehl rollt nicht mehr hoch, und die Rezepte ändern
stillschweigend ihre Zahlen. mrp schützt nur vor laufenden
Fertigungsaufträgen, was diesen Fall gar nicht berührt.

Dazu ein Test, der eine Lücke aus der liquid-Umstellung schliesst: die
Stellschraube für die Teigausbeute wurde über die Rolle gesucht. Ein Brühstück
oder Altbrot bringt Wasser mit, ohne eine Flüssigkeit zu sein, und ein Rezept
aus solchen Zutaten muss einstellbar bleiben. Der Rückfall war da, geprüft war
er nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mehl, Wasser und Salz kauft eine Bäckerei ein, Vorstufen und Teige sind
Zwischenstufen — nichts davon gehört auf die Preisliste. Verkauft wird das,
was der Backschritt herstellt, und genau dort bleibt sale_ok unangetastet.

Beim Anlegen wird der Wert in die Werte geschrieben statt hinterher gesetzt:
eine Variante entsteht über die inherits-Mechanik der Vorlage, und ein erst
danach gesetzter Wert lässt die Variante den alten Stand melden.

Bewusst ohne Ausnahme für ein mitgegebenes sale_ok — default_get hat es zu
diesem Zeitpunkt längst eingetragen, eine Voreinstellung ist von einer
Entscheidung also nicht mehr zu unterscheiden. Wer sein Mehl doch über die
Theke verkauft, schreibt den Wert einmal; der Haken beim Ändern greift nur
bei einem echten Rollenwechsel und lässt diese Entscheidung stehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die beiden Arten von Stückliste werden getrennt angeschaut — die Rezeptur,
an der entwickelt wird, und der Backschritt, der daraus ein Brot macht. Dazu
zwei Filter und eine Gruppierung nach Rezeptart.

Die Tests lesen die Domain aus der Suchansicht und führen sie aus, statt nur
zu prüfen, ob der Filter da ist: vertauscht man die beiden Domains, bleibt
der Filter vorhanden und liefert trotzdem das Falsche.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Presets und der Flüssigkeits-Umbau haben fünfzehn Strings hinterlassen,
die nie übersetzt wurden — Mehl- und Sauerteignamen, "Flüssigkeit",
"Gesamtflüssigkeit" und die Sperrmeldung standen auf Englisch in einer sonst
deutschen Oberfläche. Die Datei ist neu aus dem Export aufgebaut, damit
nichts weiter unbemerkt zurückbleibt.

Dabei fiel auf, dass der Dateikopf noch baker_recipe_editor nannte, ein Rest
der Umbenennung. Die beiden Zeitstempel aus dem Export bleiben draußen, sonst
ändert sich die Datei bei jedem Export.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Hooks liefen bisher nicht mit, deshalb kommt ihr Ergebnis in einem Zug:
ruff-format und prettier über Python und XML, das generierte README.rst.

Zwei Befunde waren echt und nicht bloß Form. pylint_odoo verlangt
self.env._ statt des importierten _; das ist seit 17.0 der Weg und der
Kern nutzt ihn selbst. Und im Readme-Fragment war eine Überschrift zu kurz
unterstrichen, woran die README-Erzeugung scheiterte.

Die Hilfetexte sind nur umbrochen, nicht umformuliert -- Python fügt die
Teile beim Übersetzen zusammen, der msgid bleibt also derselbe und die
Übersetzungen bleiben gültig.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Jeder Punkt daraus steht im Modul: die Marker an Zutat und Stückliste, die
sieben Preset-Zutaten mit Rolle und Wasseranteil, die fünf Sauerteige mit
ihrer TA, die Sperre einer mehrfach verwendeten Vorstufe, Englisch und
Deutsch. Der Punkt "presets should not be editable" ist nicht offen, sondern
abgelöst: noupdate statt Schreibverbot, dafür Löschschutz solange in
Verwendung.

Eine abgearbeitete Liste wird gelöscht und nicht als Erledigt-Datei
weitergeschleppt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Versäuerungsgrad ist das versäuerte Mehl geteilt durch das Gesamtmehl.
Entscheidend ist, was als versäuert zählt: ein Brühstück oder ein Hefevorteig
bindet ebenso Mehl und ist kein Sauerteig. Deshalb eine ausdrückliche
Kennzeichnung an der Zubereitung statt einer Ableitung aus "ist eine
Vorstufe".

Unterhalb einer markierten Stufe wird nicht weiter gefragt: ihr ganzer
Mehlgehalt ist versäuert, das Anstellgut eingeschlossen. Das entspricht der
Sache und spart die Rekursion.

Die fünf Presets und die Sauerteige der Demorezepte sind markiert, das
Brühstück nicht. Frisch installiert ergibt das 41,9 % für das Berliner
Roggenmischbrot und 33,6 % für das Neudorfer -- beides im branchenüblichen
Bereich für Roggen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Statustabelle endete dort, wo das Modul zum ersten Mal lief. Seither sind
vier Dinge dazugekommen -- noupdate statt Schreibverbot mit Löschschutz, der
Verkaufsausschluss für Teige und Rezeptzutaten, die getrennte Suche und die
Versäuerung. Jeweils mit dem Grund, nicht nur mit dem Was.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Gegenentwurf zum Baum, jetzt ohne ihn: das flache Blatt, das Anwenden in
die mehrstufige Struktur, die Wiedererkennung vorhandener Zubereitungen und
der Einstieg aus einer bestehenden Rezeptur.

Die Verhältnisrechnung -- zwei Zubereitungen auf Anteile ihrer Gesamtmasse
normieren und vergleichen -- liegt hier und nicht in der Grundlage. Sie ist
kein allgemeiner Dienst, sondern der Kern dieser einen Entscheidung: vor dem
Anlegen nachsehen, ob es die Zubereitung schon gibt.

Neun Tests, unverändert grün, einschliesslich der Kalibrierung gegen das
veröffentlichte Neudorfer Rezept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Enthält auch die automatischen Felder des Transient-Modells -- Produkt,
Sequenz, die Audit-Spalten. Sichtbar davon ist "Produkt" in der Zeilenliste.

Die Datei ist mit polib geschrieben statt von Hand: gettext verkettet die
Folgezeilen eines umgebrochenen msgstr, ein per Texteditor eingefügter
Einzeiler hängt die alte Fassung also stillschweigend hinten an.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ergebnis der Hooks in einem Zug: ruff-format und prettier, pyproject.toml von
whool, das generierte README.rst. Dazu self.env._ statt des importierten _,
wie pylint_odoo es seit 17.0 verlangt.

Das Modul hatte kein Readme -- das war eine echte Beanstandung, nicht Form.
Beim Schreiben fiel auf, dass ich den Knopf falsch im Kopf hatte: er heißt
"Develop as a formula sheet", und das Blatt öffnet bereits gefüllt, weil die
Aktion action_load gleich mit aufruft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Was beim Entwickeln im Blick sein muss, steht jetzt oben: theoretische und
tatsächliche TA, Versäuerung, Salz, Gärverlust, die Mehle mit ihrem Anteil
und das Teiggewicht.

Die tatsächliche TA ist die eine Zahl, nach der gesteuert wird, also ist sie
die eine, die man schreiben kann: eingetragen verschiebt sie das Wasser des
Hauptteigs -- der letzten Stufe, nach derselben Regel, nach der das Blatt
ohnehin geht. Wo kein Wasser steht, nimmt die nächste Flüssigkeit die
Anpassung, und ihr eigener Wasseranteil bestimmt, wie viel davon nötig ist.
Eine Zubereitung gibt ihr Wasser nicht wieder her; darunter wird die Zeile
negativ, und das zeigt das Blatt rot an, statt den Wunsch stillschweigend zu
verweigern.

Dabei fiel ein Fehler auf, den kein Test hatte: bei einer Zeile auf eine
bestehende Zubereitung ist der Prozentwert das versäuerte Mehl, nicht die
Masse. Alles, was die Zubereitung mitbringt, folgt aus dieser Masse -- bei
TA 200 sind 30 % Mehl eben 60 % Masse. Vorher fehlte die halbe Flüssigkeit.

Teiggewicht und Gärverlust hängen zusammen: das Gewicht ist, was herauskommt,
der Verlust muss also obendrauf hinein. Beides wird beim Einlesen aus der
Rezeptur übernommen und beim Anwenden zurückgeschrieben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine Bäckerei arbeitet am Brot; der Teig ist dessen Zwischenstufe und wird
nicht verkauft. Der Knopf sitzt deshalb am Backschritt, und die Aktion sucht
sich den Teig darunter -- die Zutat mit einer eigenen Rezeptur.

Eine Teigstückliste beantwortet die Frage weiterhin mit sich selbst, damit
der Aufruf nicht davon abhängt, von wo er kommt.

Damit ist die Liste abgearbeitet und wird gelöscht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Was seit dem ursprünglichen Plan dazugekommen ist: der Einstieg am Brot, die
Kennzahlen im Kopf, die schreibbare TA -- und der Fehler, dass ein Prozentwert
auf einer Zeile zur bestehenden Zubereitung Mehl meint und nicht Masse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher trug die Reihenfolge die Struktur: die letzte Stufe war der Teig, alles
davor eine Vorstufe davon. Das kann nur zwei Ebenen ausdrücken -- ein
Anstellgut landete zwangsläufig neben dem Sauerteig statt darin.

Jetzt sagt eine Stufe, in welche Stufe sie geht. Dass eine Vorstufe nicht in
mehreren weiterführenden Stufen genutzt werden kann, ist damit keine Regel,
die man prüfen müsste, sondern eine Form, die sich nicht hinschreiben lässt:
die Beziehung ist ein einzelner Verweis.

Welche Stufe der Teig ist, wird ebenfalls gesagt statt geraten. Wer aus der
Reihenfolge schließt, hat beim zweiten wurzellosen Datensatz schon verloren --
und genau der ist der interessante Fall: eine Vorstufe, die niemand
angeschlossen hat. Nichts davon käme im Rezept an, deshalb warnt das Blatt,
solange es geschrieben wird, statt es beim Anwenden stillschweigend fallen zu
lassen.

Das Anwenden folgt der Beziehung und baut jede Stufe rekursiv: ein Codepfad
für jede Tiefe. Der Test dazu baut Anstellgut -> Sauerteig -> Teig; lässt man
die Mehlmenge der Unterstufen weg, meldet er 35 statt 40 %.

Die Sauerteig-Markierung wandert von der Zeile an die Stufe, wo sie
hingehört -- an der Zeile steht sie nur noch zur Anzeige.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
odoo force-pushed odoo/19.0-recipe_wizard_stages from a5d42ce7d7 to 535b0ee9dd 2026-09-22 20:54:19 +00:00 Compare
odoo force-pushed odoo/19.0-recipe_wizard_stages from 535b0ee9dd to 330432396e 2026-09-22 20:59:08 +00:00 Compare
odoo force-pushed odoo/19.0-recipe_wizard_stages from 330432396e to 1cb1dc6fb4 2026-09-22 21:06:55 +00:00 Compare
odoo force-pushed odoo/19.0-recipe_wizard_stages from 1cb1dc6fb4 to dcd4672a4e 2026-09-23 04:43:20 +00:00 Compare
Der Einstieg am Backschritt suchte den Teig an seiner eigenen Rezeptur --
und genau die fehlt, solange nichts entwickelt ist. Ein neues Brot lief damit
in einen Fehler statt in ein leeres Blatt, also ausgerechnet auf dem Weg, auf
dem ein Rezept beginnt.

Ohne Rezeptur ist der Teig die Zutat, die keine ist: Mehl, Flüssigkeit und
Salz tragen eine Rolle, ein Teig trägt keine. Bleibt genau eine solche Zeile
übrig, ist sie es.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Es holt das Blatt danach frisch vom Server, also war alles verloren, was nur
im Browser stand. Derselbe Fehler wie beim Anwenden, nur eine Schaltfläche
weiter -- beide sichern jetzt selbst, und ein Test prüft die Reihenfolge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Einlesen wurden die inneren Prozentwerte einer Vorstufe mit deren
Prozentwert in der Rezeptur skaliert. Das stimmt nur, solange die Vorstufe
Mehl trägt: dann ist ihr Prozentwert das versäuerte Mehl, und der entspricht
zufällig dem Anteil der Charge, den das Rezept verwendet.

Ein Brühstück trägt kein Mehl und wird nach Masse dosiert. Sein Prozentwert
hat mit dem Chargenanteil nichts zu tun, und das Blatt zeigte seine Zutaten
entsprechend zu klein -- im gemessenen Fall TA 133 statt 145. Genau das war
das Gefühl, dass die TA nicht zur Formularansicht passt.

Skaliert wird jetzt mit dem Anteil, den das Rezept von der Charge nimmt:
verwendete Menge durch Ausbeute. Für eine mehlhaltige Vorstufe ist das
dieselbe Zahl wie vorher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
**Der Fokus bleibt beim Tippen.** Der Zeilenschlüssel trug den Wert, also
wurde die Zeile bei jedem Tastendruck neu gebaut. Der Schlüssel war überflüssig:
eingebaut hatte ich ihn gegen eine mitskalierte Zeile, die ihren alten Wert
zeigte -- deren Ursache war aber, dass der Rechner damals an `change` hing und
der Test nur `input` auslöste. Ein Test hält jetzt fest, dass auch ein Feld,
in das schon getippt wurde, der Skalierung folgt.

**Die tatsächliche TA ist eingebbar.** Eingetragen verschiebt sie das Wasser
des Hauptteigs; was andere Zeilen schon tragen, lässt sich nicht herausnehmen,
darunter wird die Zeile negativ und das Blatt sagt es.

**Zutaten und Stufen lassen sich entfernen.** Örtlich sofort, damit die
Kennzahlen folgen, und auf dem Server gleich mit -- zurückgeschrieben wird
nach Id, und ein Schreibvorgang löscht nichts. Was in eine entfernte Stufe
ging, geht dorthin, wo sie hinging.

**Der Wähler "geht in" ist weg.** Eine Vorstufe steht jetzt als Zutat in der
Liste der Stufe, in die sie geht, mit dem Mehl, das sie mitbringt. Wo eine
Stufe angelegt wird, ist damit die ganze Beziehung: der Knopf sitzt in der
Stufe, zu der die neue gehört.

**CR: markierte Zutaten gleichen einander aus.** Ein Kettensymbol je Zeile.
Was der einen zukommt, geht den anderen derselben Art ab, im Verhältnis, in
dem sie zueinander stehen. Die Mehle gleichen dabei gegen die 100 % des
Rezepts aus -- das ist die Regel, nach der auch der Graph die direkten
Mehlzeilen den Rest aufteilen lässt; Flüssigkeit und Salz haben keine solche
Basis und behalten schlicht ihre Summe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gegenstück zur tatsächlichen TA, und deshalb Zeile für Zeile daran gebaut:
eingetragen verschiebt es das Salz des Hauptteigs. Was eine Vorstufe schon
mitbringt, lässt sich nicht herausnehmen, also geht nur die Differenz auf
diese Zeile -- darunter wird sie negativ, statt die Eingabe abzulehnen.

Die Regel steht im Modell, nicht in der Oberfläche, und hat dort ihre eigenen
Tests; der Browser rechnet dasselbe, damit die Zahl beim Tippen mitläuft.

Beide gesteuerten Felder färben sich jetzt rot, sobald die Zeile, die sie
bewegen, unter null gegangen ist. Bisher sagte das nur der Hinweis über der
Liste, und damit stand die Ursache weit weg von der Stelle, an der man sie
verursacht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Als Knopf im Formular ersetzte es serverseitig jede Stufe und jede Zeile,
während das Blatt im Browser die alten Ids weiter hielt. Das nächste
Speichern schrieb damit auf Datensätze, die es nicht mehr gab -- ein Test
hält jetzt fest, dass genau das eine MissingError wirft.

Es sitzt deshalb im Blatt und lädt danach neu. Dass es Eingaben verwirft,
steht jetzt in seinem Namen, statt eine Überraschung zu sein.

Die Beschriftungen dazu geradegezogen: "Speichern" statt "Blatt sichern"
(Odoo sagt speichern), "Anwenden und schließen" statt "Sichern und anwenden"
-- der Knopf tut beides, und das Schließen war vorher nirgends zu lesen. Der
Titel des Schlosses hing als Ausdruck im Attribut und war damit gar nicht
übersetzbar.

Dazu ein Durchstich über beide Knöpfe: Nutzlast erzeugen, ändern, speichern,
anwenden und die entstandene Stückliste nachrechnen. Die Oberflächentests
arbeiten gegen Attrappen und zeigen nur die Reihenfolge der Aufrufe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
odoo force-pushed odoo/19.0-recipe_wizard_stages from 98c277555c to 111bc5cc37 2026-09-23 16:53:58 +00:00 Compare
Die Suche nach Wasser und Salz im Hauptteig nahm die erste Zeile, die davon
etwas enthält -- und eine Vorstufe enthält beides. Eine Eingabe im Kopf
skalierte damit die ganze Vorstufe statt einer Zutat des Teigs. Genau das
waren die zufälligen Werte in einem Rezept ohne Salz im Hauptteig.

Gesucht wird jetzt nur unter den eigenen Zutaten des Teigs, und Salz heißt
Salz. Gibt es keine solche Zeile, ist das Feld nicht mehr beschreibbar --
vorher nahm es Eingaben an, die nirgends ankamen.

Dazu drei Kleinigkeiten aus demselben Bericht:

Die TA liest sich ohne Nachkommastellen. Und die Felder im Kopf hatten keinen
Entwurfszustand: sie wurden bei jedem Tastendruck neu formatiert, wodurch der
Cursor hinter einem gerade gesetzten Punkt landete und die nächste Ziffer auf
der falschen Seite davon. Jetzt bleibt stehen, was getippt wird, bis das Feld
verlassen wird -- dieselbe Regel wie in den Zeilen.

Beim Ausgleichen lässt sich nur noch eine Zeile je Art markieren. Mit
mehreren verschob eine Eingabe gleich mehrere Zeilen, und welche, war nicht
zu sehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
odoo force-pushed odoo/19.0-recipe_wizard_stages from 3b046da54a to ca84efb5de 2026-09-23 17:04:30 +00:00 Compare
odoo force-pushed odoo/19.0-recipe_wizard_stages from ca84efb5de to bf14718b49 2026-09-23 18:08:18 +00:00 Compare
odoo force-pushed odoo/19.0-recipe_wizard_stages from bf14718b49 to 7f949b62bb 2026-09-23 19:19:33 +00:00 Compare
Beide sind Zubereitungen, und sie werden verschieden gebraucht: ein
Anstellgut wird geführt und geht als Zutat in eine Stufe ein, eine Vorstufe
wird für ein Rezept angesetzt und ist eine eigene Stufe. Ohne diesen
Unterschied kann das Formelblatt nicht entscheiden, was beim Einlesen zur
Stufe wird und was Zutat bleibt.

Mit der Sauerkeit hat das nichts zu tun: die trägt das Anstellgut, und ein
Sauerteig wird daran erkannt. Ein Hefevorteig ist eine Vorstufe ohne Säure,
ein Weizenanstellgut ein Anstellgut mit.

Die fünf Presets und das Demo-Anstellgut sind entsprechend markiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ausgeblendet war es falsch herum gedacht: ein Bäcker wiegt es ab, also
gehört es in die Zutatenliste seiner Stufe wie jede andere Zutat auch.

Was es von einer Vorstufe unterscheidet, steht jetzt am Produkt, und das
Einlesen richtet sich danach: eine Vorstufe wird zur eigenen Stufe, ein
Anstellgut bleibt Zutat. Vorher entschied das die Tiefe, in der es gefunden
wurde -- ein Anstellgut unmittelbar im Teig wäre zur Stufe geworden, und im
Blatt hätte eine Charge Anstellgut gestanden, die niemand ansetzt.

Die Sauerteig-Marke ist weg: sie wird ohnehin erkannt, und zweimal dasselbe
zu sagen kostet eine Zeile, die das Blatt lieber für Zutaten ausgibt. Kopf
einer Stufe ist jetzt eine Zeile -- Name links, alles Handelnde rechts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ich hatte "nicht mehr als eine je Art" gelesen, gemeint war das Paar: was der
einen zukommt, geht der anderen ab. Mit nur einer Markierung gab es kein
Gegenstück, und der Ausgleich tat nichts.

Schlimmer als der Fehler ist, wie er durchkam: der Test beschrieb die falsche
Regel und hat sie damit festgeschrieben, statt sie zu melden. Er prüft jetzt
das Paar -- und dass eine dritte Markierung die älteste löst, statt eine
beliebige. Auf die alte Regel zurückgedreht fällt er sofort durch.

Dazu bleibt die Kopfzeile beim Blättern stehen: die Kennzahlen sind das,
wonach gesteuert wird, und dafür nach oben zu scrollen ist das Gegenteil
davon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Sauerteig gärt zwölf Stunden, ein Teig eine -- eine Zahl fürs ganze Blatt
konnte für beide nur falsch sein. Jede Stufe nennt jetzt ihren eigenen, und
er steht in ihrer Kopfzeile: kurz "Verlust", weil Platz zählt.

Damit wird auch die Charge anders gerechnet: eine Vorstufe gibt ihre
Ausbeute weiter, nicht das, was in sie hineinging. Was der Teig am Ende
abgibt, ergibt sich also über alle Stufen hinweg, jede um ihren Verlust
vermindert.

Beim Einlesen kommt der Verlust aus der Rezeptur selbst: die Ausbeute ist,
was herauskam, die Zeilen sind, was hineinging, und die Differenz ist er --
es gibt nichts, was zusätzlich nachgeführt werden müsste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine gezogene Zutat stand danach zweimal im Blatt. Beim Loslassen hält das
Sortable noch einen Klon der Zeile dort, wo sie hin soll, und die Zeile selbst
dort, wo sie war -- die Reihenfolge von der Tabelle abzulesen fand die Zeile
also doppelt. Gespeichert wurde nichts davon, weil nach id geschrieben wird;
aber das Duplikat zu löschen löschte den einzigen Datensatz. Die Reihenfolge
kommt jetzt aus dem Nachbarn, den das Sortable beim Loslassen nennt.

Der bisherige Test rief die Umsortierung direkt auf und zog nie etwas. Der
neue zieht wirklich und fällt mit dem alten Code auf dem doppelten Schlüssel
durch.

Dazu lassen sich die Vorstufen ziehen wie jede Zutat. Eine Vorstufe ist eine
Zutat der Stufe, in die sie geht, also teilt sie deren Nummerierung: Zeilen
und Vorstufen sortieren gemeinsam, und die Stufen des Blatts werden in der
Reihenfolge gelesen, in der der Teig sie verwendet. Das Brühstück oben im
Hauptteig steht damit auch vor dem Sauerteig. Die Rezeptur baut ihre Zeilen in
dieser Reihenfolge, und das Einlesen übernimmt die der Stückliste, statt die
Vorstufen hinten anzuhängen.

Innerhalb seiner Stufe bleibt ein Zug: eine Zeile in eine andere zu ziehen
würde ändern, woraus die besteht, und das sagt ein Ziehen nicht.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Der Brotkrumen nannte das Blatt "bakery.recipe.wizard,1": Modell und id, weil
der Assistent keinen Namen hatte. Er heißt jetzt wie der Teig, um den es geht.

Der Hinweis, dass das Mehl nicht auf 100 % kommt, steht jetzt im Kasten, der
beim Blättern stehen bleibt. Gelesen wird er, während weiter unten eine Zahl
geändert wird, und dort war er gerade weggescrollt.

Solange das Mehl nicht aufgeht, bietet jede Mehlzeile "auf 100 %" an: sie
bekommt, was fehlt. Es geht derselbe Weg wie eine Eingabe -- eine gesperrte
Stufe behält ihr Verhältnis und wächst als Ganzes, bis das Mehl aufgeht.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
"auf 100 %" stand auch am Anstellgut: seine Prozentzahl ist Mehl, also zählte
es als Mehlzeile. Aufgefüllt wird ein Rezept aber mit einem Mehl, nicht mit
Anstellgut -- der Knopf fragt jetzt nach der Rolle, nicht nach dem Mehlgehalt.

Und er brach unter das Feld um, weil das Eingabefeld als Block gesetzt ist;
jede Mehlzeile wurde damit höher, sobald das Mehl nicht aufging.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin +refs/pull/5/head:odoo/19.0-recipe_wizard_stages
git switch odoo/19.0-recipe_wizard_stages

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 19.0
git merge --no-ff odoo/19.0-recipe_wizard_stages
git switch odoo/19.0-recipe_wizard_stages
git rebase 19.0
git switch 19.0
git merge --ff-only odoo/19.0-recipe_wizard_stages
git switch odoo/19.0-recipe_wizard_stages
git rebase 19.0
git switch 19.0
git merge --no-ff odoo/19.0-recipe_wizard_stages
git switch 19.0
git merge --squash odoo/19.0-recipe_wizard_stages
git switch 19.0
git merge --ff-only odoo/19.0-recipe_wizard_stages
git switch 19.0
git merge odoo/19.0-recipe_wizard_stages
git push origin 19.0
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
odoo/odooapps!5
No description provided.