Changelog
Release notes of the zSYNC odoo modules. Every module carries its own version; a block below tells which module changed and from which version to which one.
This page is generated from the patchnotes of the modules - please do not edit it directly. New entries are added by the "patchnotes to changelog" workflow on every push to the 19.0 branch.
2026-09-04
zbsync 2.9 → 2.10
- Pipeline-Formular: leerer Chart-Tab entfernt.
- Nachtraegliche Patchnote zu einer Aenderung aus #4462, die dort ohne Eintrag und ohne Version-Bump gemerged wurde.
- Im Pipeline-Formular gab es zwei Tabs namens "Chart": einen leeren aus zbsync selbst und den eigentlichen aus dem Modul zbsync_pipeline_widget, in dem die Pipeline auch wirklich gezeichnet wird. Der leere Tab ist weg.
- Wer zbsync_pipeline_widget nicht installiert hat, hat danach gar keinen Chart-Tab mehr - vorher war er dort leer und ohne Inhalt.
- Zum Testen: Eine Pipeline oeffnen. Es darf nur noch ein Tab "Chart" zu sehen sein, und darin die gezeichnete Pipeline.
zbsync_ai_code 1.1 → 1.2
- KI-Mapping-Assistent erfindet keine Felder mehr auf echten Odoo-Modellen.
- Nachtraegliche Patchnote zu den Aenderungen aus #4462, die dort ohne Eintrag gemerged wurden.
- Wenn der Assistent einen Pfad vorgeschlagen hat, den es auf dem Odoo-Modell nicht gibt, wurde dafuer stillschweigend ein Platzhalter-Feld angelegt. Auf einem echten Odoo-Modell ist das immer falsch. Solche Vorschlaege bleiben jetzt auf der betroffenen Seite leer. Bei extern definierten Backends (JSON) legt der Assistent weiterhin Platzhalter an, weil dort vorher nicht feststeht, welche Felder vorkommen.
- Ausserdem sitzt der Button "+ Mapping" jetzt in der Mapping-Liste selbst statt im KI-Modul, damit er auch ohne installierten Assistenten da ist.
- Zum Testen: Bei einem Mapper mit einem Odoo-Modell als Zielbackend den Assistenten ueber "Map" laufen lassen - in den erzeugten Mappings darf kein Feld auftauchen, das es auf dem Modell nicht gibt.
zbsync_mapper 2.4 → 2.5
- Mapper: Nacharbeiten zum Umbau der Backend-Auswahl (#4462).
- Vier Punkte aus dem Review, die beim Merge offen geblieben sind:
- Automatisch angelegte Backends wurden doppelt erzeugt. Der Name eines solchen Backends enthaelt den Pipeline- und den Mappernamen, gesucht wurde aber genau ueber diesen Namen. Wer die Pipeline oder den Mapper umbenannt hat, bekam beim naechsten Mal ein zweites Backend daneben - und ab dann lief nur noch das neue mit. Gesucht wird jetzt ueber die Mapper-Nummer im Namen, die sich nicht aendert; alte Backends ohne diese Nummer werden weiterhin gefunden und einmalig umbenannt.
- In der Mapping-Tabelle war nicht mehr zu sehen, welche Zeile man angeklickt hat. Die neue Einfaerbung der Zeilenraender hat die Markierung von Odoo ueberdeckt - fuer die ausgewaehlte Zeile, die gerade bearbeitete und die unter dem Mauszeiger. Solange Odoo eine Zeile hervorhebt, bleibt die Einfaerbung jetzt aussen vor.
- Im Dark Mode sah die Mapping-Tabelle unveraendert aus: dort galt noch die alte, ab etwa Ebene sieben unlesbare Grau-Abstufung, die die neue Einfaerbung komplett verdeckt hat. Der Dark Mode zieht jetzt nach, mit Helligkeiten, die zu dunklem Hintergrund passen.
- Wer die Aktion einer Mapping-Zeile bewusst gesetzt hatte (z.B. auf Code oder Default) und danach das Zielfeld gewechselt hat, verlor diese Einstellung stillschweigend. Abgeleitet wird die Aktion jetzt nur noch, solange sie auf ihrer Voreinstellung steht.
- Ausserdem laeuft das Nachladen der Unterfelder eines Feldes jetzt mit Systemrechten. Es ist eine technische Spiegelung des Modells, hat aber geschrieben - Anwender, die Mappings pflegen duerfen, aber die Backend-Felder nicht, bekamen beim Oeffnen der Feldauswahl eine Rechte-Fehlermeldung.
- Zum Testen: (a) Bei einem Mapper mit automatisch angelegtem Backend die Pipeline umbenennen, dann eine Mapping-Zeile anlegen - es darf kein zweites Backend entstehen. (b) In der Mapping-Tabelle eine Zeile anklicken und mit der Maus darueberfahren: die Markierung muss sichtbar sein, auch bei tief verschachtelten Zeilen. (c) Dasselbe im Dark Mode.
- (d) Aktion einer Zeile auf "Code" stellen, danach das Zielfeld wechseln - die Aktion muss "Code" bleiben.
2026-08-31
zbsync 2.8 → 2.9
- Beim Anlegen einer Instanz werden jetzt alle Line-Einstellungen von der Pipeline-Line auf die Instanz-Line uebernommen: "Condition", "Group continue here", "Batch execution in order", "Queuejob Channel", "Queuejob Priority", "Keep Input Filter", "Path Content", "Retry Pattern", "Abort on error", "Skip record on error" und "Continue immediately". Bisher standen bei den ersten fuenf die Defaults (Condition z.B. immer "True"), obwohl im Lauf die Pipeline-Werte benutzt wurden - in der Instanz sah es also so aus, als waere die Einstellung verloren gegangen. Die anderen fuenf zeigten den Pipeline-Wert nur an: aenderte man sie in der Instanz, aenderte man die Pipeline mit.
- Alle diese Felder werden ab jetzt aus der Instanz-Line gelesen. Damit kannst du sie - wie Range und Filter schon vorher - pro Instanz aendern, ohne die Pipeline anzufassen. Der gelbe Hinweis dazu steht jetzt oben im Formular, weil er fuer alle Einstellungen darin gilt.
- "Continue immediately" ist im Line-Formular nicht mehr readonly und in der Zeilenliste der Instanz als optionale Spalte verfuegbar - sonst koennte man es pro Instanz gar nicht umstellen.
- Zum Testen: In der Pipeline eine Line oeffnen, unter "Filtering and Conditions" eine Condition eintragen, speichern, "Test Run" -> in der erzeugten Instanz die Line ueber das Zahnrad oeffnen: dort steht jetzt dieselbe Condition. Wird sie dort geaendert, gilt die Aenderung nur fuer diese Instanz.
- Bestehende Instanzen werden beim Update einmalig aus ihrer Pipeline nachgezogen, damit laufende Instanzen unveraendert weiterarbeiten.
zbsync_pipeline_widget 2.3 → 2.4
- Die Instanz-Ansicht zeigt in den Node-Kacheln jetzt die Einstellungen der Instanz statt derer der Pipeline. Betrifft "Keep Input Filter", "Path Content", "Retry Pattern", "Abort on error", "Continue immediately" und den Enabled-Zustand - die kamen bisher aus der Pipeline-Line und wichen damit von dem ab, womit die Instanz tatsaechlich laeuft.
- Zum Testen: Eine Instanz oeffnen, an einer Line ueber das Zahnrad z.B. das Retry Pattern aendern und speichern -> die Kachel in der Flow-Ansicht zeigt den geaenderten Wert, die Pipeline bleibt unveraendert.
zbsync_mapper 2.3 → 2.4
- Formular fuer Backend-Felder: fehlendes Feld is_new nachgetragen.
- Das Formular hinter "Create and Edit..." blendet oben rechts ein Baendchen "New" ein, solange ein Feld nur als Platzhalter angelegt ist. Die Bedingung dafuer greift auf is_new zu, das Feld war im Formular aber gar nicht eingebunden. Odoo 19 und 18 lassen das durch, Odoo 17 verweigert beim Portieren die Ansicht - dort laesst sich das Modul damit nicht laden.
- Das Feld ist jetzt unsichtbar im Formular eingebunden, damit die Ansicht auf allen Versionen gleich aufgebaut ist.
- Zum Testen: Bei einem Mapper mit ausgeschaltetem "Lock Field Creation" im Feldpicker "Create and Edit..." waehlen. Das Formular oeffnet sich wie bisher; bei einem als neu markierten Feld ist rechts oben weiterhin das Baendchen "New" zu sehen.
2026-08-28
zbsync 2.7 → 2.8
- Neue Option "Skip record on error" pro Pipeline-Line (Tab "Error Handling" bzw. in der Zeilen-Liste als optionale Spalte). Ist sie aktiviert, wird ein einzelner Datensatz, der beim Verarbeiten einen Fehler wirft, uebersprungen und als Warnung geloggt, statt den ganzen Batch abzubrechen. Batch und Pipeline laufen mit den uebrigen Datensaetzen weiter.
- Zum Testen: In der Pipeline die betroffene Line oeffnen -> "Error Handling" -> "Skip record on error" anhaken. Anwendungsfall: ein vorgelagerter Step liefert fuer manche Datensaetze eine leere Antwort, die den Lauf nicht abbrechen darf. Default ist aus -> bestehendes Verhalten unveraendert.
2026-08-27
zbsync_mapper 2.2 → 2.3
- "Create and Edit..." on a Source/Dest Field picker now opens a proper form (name, label, type, has sub-fields) instead of Odoo's raw auto-generated fallback form.
- Mappers now default to Lock Field Creation = on, so Source/Dest Field pickers only offer existing backend fields instead of silently creating a bogus one from a typo. This only affects the mapping editor — already-configured mappings and pipeline runs are unaffected. Existing mappers are migrated to locked on upgrade — disable the toggle above the mapping table on a given mapper to restore the old on-the-fly creation behaviour for it.
- Replaced the mapping table's flat per-level gray row darkening (which became illegible a few levels into a deeply nested mapping) with a gradient tinted by each row's own Source/Dest Path root color, matching the path breadcrumb badges. Each border darkens independently based on how deep that specific side is nested, so a row where only the destination goes several levels deep still reads clearly.
- Fixed an OwlError crash opening any mapper, caused by the Source/Dest Field picker's create/lock logic (LockableMany2OneField) using an Odoo <19 field-registry API that no longer exists in Odoo 19.
- Fixed selecting an Odoo model with a large field graph (e.g. project.project) as a mapper backend hanging indefinitely — backends now only sync the root level eagerly; deeper comodel levels sync on demand as you actually navigate into them in the mapping table, so a hub model resolves instantly.
- Fixed navigating into a comodel's own fields (e.g. picking a many2one, then adding a child mapping under it) sometimes showing an empty Source/Dest Field dropdown even after the fix above, because the "New Child Mapping" row doesn't exist in the database yet when you need to pick its field.
- Selecting a Dest Field with no Source Field set now infers the mapping Action from the dest field's own type (e.g. a many2many still gets action=List Object), the same way it already did when a Source Field was picked.
2026-08-19
zbsync 2.6 → 2.7
- Daten im ZebrooSet koennen jetzt sortiert werden - so wie man es von Odoo Recordsets kennt:
data.sorted("name"), absteigend mitdata.sorted("name", reverse=True), nach mehreren Feldern mitdata.sorted("land,name")bzw.data.sorted(["land", "name"])und bei Bedarf auch mit einer eigenen Funktiondata.sorted(lambda rec: len(rec["name"])). - Bisher lief so ein Aufruf im Transformer/Python-Code in einen Fehler ("AttributeError: sorted").
- Das funktioniert auf allen Ebenen der Daten: auf dem kompletten Datensatz, auf einer Unterliste (
data.lines.sorted("pos")) und auch dann, wenn im ZebrooSet echte Odoo-Records stecken - dann wird ueber die Odoo-Felder sortiert. Feldnamen werden wie ueberall im ZebrooSet ohne Ruecksicht auf Gross-/Kleinschreibung gefunden. - Leere Werte (nicht gesetzt, None, False) fuehren nicht mehr zum Abbruch, sondern werden nach vorne sortiert; auch gemischte Werttypen in einem Feld brechen die Sortierung nicht ab. Das Original bleibt unveraendert, man bekommt eine sortierte Kopie zurueck.
- Zum Nachpruefen: in einer Pipeline/einem Transformer z.B.
data = data.sorted("name")setzen und die Reihenfolge der Records in der Pipeline-Vorschau ansehen. Heisst ein Feld in den Daten selbst "sorted", hat es weiterhin Vorrang - die Sortierung ist dann ueber_sorted(...)erreichbar.
zbsync_odoo 2.2 → 2.3
- Records eines angebundenen Fremd-Odoos koennen jetzt ebenfalls sortiert werden:
data.sorted("name")bzw.data.sorted("name", reverse=True)oder nach mehreren Felderndata.sorted("land,name"). Sortiert wird dabei vom entfernten Odoo selbst (als Suchreihenfolge), es werden also keine zusaetzlichen Felder ueber die Verbindung gelesen. Ohne Feldangabe gilt die Standardsortierung des Modells. - Weil das auf der Gegenseite passiert, sind hier nur Feldnamen moeglich - eine eigene Sortierfunktion (lambda) laeuft in eine verstaendliche Fehlermeldung.
- Zum Nachpruefen: in einer Pipeline mit einer Odoo-Verbindung Records grabben und im folgenden Schritt
data = data.sorted("name")setzen; die Reihenfolge in der Vorschau muss der Sortierung entsprechen.
zbsync_web 1.5 → 1.6
- OAuth2-Webrequests scheiterten mit "InsecureTransportError: OAuth 2 MUST utilize https", wenn die hinterlegte Ziel-URL fuehrende oder nachgestellte Leerzeichen enthielt: oauthlib prueft die URL mit startswith("https://"), was bei " https://..." fehlschlaegt. Die in _build_url zusammengesetzte URL wird jetzt getrimmt, sodass solche versehentlichen Leerzeichen den Request nicht mehr blockieren.
- Test: Bei einer Web-URL mit OAuth2-Auth versehentlich Leerzeichen vor der URL stehen lassen und den Worker laufen lassen - der Request laeuft jetzt durch statt mit InsecureTransportError abzubrechen.
- Interne zbsync-Metadaten-Keys (mit Praefix "___" wie ___filter_to_delta, ___keys, ___no_create) landeten bei JSON-Webrequests ungefiltert im Request-Body. Strenge Kunden-APIs lehnten den Payload dann mit HTTP 400 ab (unbekanntes Feld). Diese Keys werden jetzt rekursiv aus dem JSON-Body entfernt, bevor der Request rausgeht - analog dazu, wie der Odoo-Dumper die Metadaten konsumiert. Der Odoo-/SQL-Pfad bleibt unveraendert.
- Test: Einen Web-Worker mit JSON-Body und einem Mapper mit aktiviertem "Filter Delta" / Keys laufen lassen - im gesendeten Body duerfen keine "___"-Felder mehr auftauchen, der 400er bleibt aus.
2026-08-18
zbsync 2.5 → 2.6
- Heimruf (call_home) meldet jetzt auch die angelegten Connections.
- Der taegliche Cronjob "zync:call_home" uebertraegt zusaetzlich zu den Pipeline- und Mapping-Zahlen die Anzahl der Connections sowie je Connection Typ, interne ID und Bezeichnung. Die ID bleibt bei einer Umbenennung gleich, dadurch wird eine umbenannte Connection nicht als neue gezaehlt.
- Adressdaten, Zugangsdaten und Konfigurationsinhalte werden weiterhin nicht uebertragen.
- Neu: Ist die Umgebungsvariable DEVMODE gesetzt, wird gar nichts gemeldet - Entwicklungs- und Testumgebungen tauchen damit nicht mehr in der Auswertung auf.
- Zum Testen: Einstellungen -> Technisch -> Automatisierung -> Geplante Aktionen -> "zync:call_home" manuell ausfuehren. Mit gesetztem DEVMODE erscheint im Log "DEVMODE gesetzt, kein Heimruf.", ohne DEVMODE laeuft der Job durch; bei nicht erreichbarem Backend bleibt er gruen und loggt "zSYNC call_home failed: ...".
2026-08-11
zbsync 2.4 → 2.5
- Kanban-Vorlage der Pipeline-Schritte auf die aktuelle Odoo-Syntax gebracht.
- Odoo 18 erwartet in Kanban-Ansichten eine Vorlage namens "card"; der alte Name "kanban-box" wird nur noch mit einem Hinweis im Log geduldet.
- Zum Testen: Die Ansicht ist inhaltlich leer und wird von keiner Aktion aufgerufen - sichtbar aendert sich nichts.
- SOAP-Verbindungen auf odoo.sh wieder nutzbar. requests_toolbelt ist eine Abhaengigkeit von zeep, das wir fuer SOAP einsetzen. Es war bisher nicht in den Anforderungen aufgefuehrt, weshalb auf odoo.sh die alte Version aus dem Betriebssystem genommen wurde. Die passt nicht mehr zum neueren urllib3, das wir mitbringen: der Import bricht mit "cannot import name 'appengine'" ab. Damit liess sich dort kein SOAP-Modul laden. Jetzt ist requests_toolbelt ab 1.0.0 verlangt.
- Zum Testen: Verbindungen -> SOAP oeffnen und eine Verbindung anlegen bzw. einen bestehenden SOAP-Schritt laufen lassen. Auf odoo.sh lief das vorher in einen Importfehler.
zbsync_odoo 2.1 → 2.2
- Update auf zbsync_odoo 2.x laeuft auch dann durch, wenn Limit/Offset am Odoo-Grabber schon weg sind.
- Beim Umzug von Limit/Offset vom Grabber auf die Domain-Zeilen hat das Migrationsskript darauf gesetzt, dass die alten Spalten in der Datenbank noch vorhanden sind. Odoo entfernt eine Spalte aber schon in dem Update, in dem das Feld aus dem Modell verschwindet. Datenbanken, die so ein Update bekommen haben (oder neu aufgesetzt wurden), bevor die Modulversion angehoben wurde, sind beim naechsten Update mit "column g.limit does not exist" stehen geblieben und liessen sich nicht mehr starten. Das Skript prueft die Spalten jetzt vorher und ueberspringt die Uebernahme, wenn es nichts zu uebernehmen gibt.
- Zum Testen: Update der Instanz einspielen. Danach in einem Odoo-Grabber den Reiter Domains oeffnen - dort stehen Limit und Offset. Bei Instanzen, die vor dem Update noch Werte am Grabber hatten, sind diese Werte in der ersten Domain-Zeile wiederzufinden.
zbsync 2.3 → 2.4
- Reihenfolge der Zeilen im Duplizieren-Assistenten festgezogen.
- Die Sequenz-Spalte im Assistenten war nur ein abgeleitetes Feld ohne eigene Spalte in der Datenbank. Dadurch liess sich nicht danach sortieren: Odoo hat das beim Laden bemaengelt, und das Duplizieren hat die Zeilen in einer beliebigen Reihenfolge abgearbeitet.
- Zum Testen: Eine Pipeline mit mehreren Schritten oeffnen und ueber "Kopie anlegen" duplizieren. Die Liste im Assistenten steht jetzt in der gleichen Reihenfolge wie die Schritte der Original-Pipeline, und die Kopie uebernimmt genau diese Reihenfolge.
zbsync_webdav 1.3 → 1.4
- Warnung der WebDAV-Bibliothek nicht mehr im Log.
- Die eingesetzte Bibliothek webdavclient3 hat beim ersten Laden eine Python-Warnung ueber eine ungueltige Escape-Sequenz geschrieben. Das ist Fremdcode, den wir nicht aendern; die Warnung wird jetzt beim Import ausgefiltert. Funktional aendert sich nichts.
- Zum Testen: Nichts zu klicken - beim Neustart bzw. Modulupdate steht die Zeile "invalid escape sequence" aus webdav3/urn.py nicht mehr im Log.
2026-08-10
zbsync 2.2 → 2.3
- Erwartete Fehler im Testmodus erzeugen kein Log-Rauschen mehr, und zwei echte Code-Warnungen sind behoben.
- Fehlgeschlagene Batches werden im Testmodus als INFO ohne Stacktrace geloggt - ein vom Test selbst provozierter Fehlschlag ist dort das erwartete Ergebnis. Die Exception steht als Kurzform in der Meldung, z. B.
- "Exception at batch 6 of instance 2 (Exception: bad found)". Im normalen Betrieb bleibt es unveraendert ERROR mit vollem Stacktrace - dort ist ein gescheiterter Batch ein echtes Problem.
- Ebenfalls auf INFO: der Receiver bei absichtlich scheiternden Pipelines, der Watchdog beim vom Test provozierten Leerlauf, und der Diff-Dump von _is_equal (ein Unterschied ist dort ein regulaeres Ergebnis - ob er ein Problem ist, entscheidet der aufrufende Test).
- Behoben: Ein Recordset wurde per "==" mit einer Klasse verglichen (zebrooset), was eine UserWarning ausloeste; und die Instanz-Zaehler der Pipeline nutzten das seit Odoo 19 veraltete read_group.
- Hintergrund: odoo.sh bewertet einen Dev-Build ueber das Build-Log.
- ERROR-Zeilen und Tracebacks ergaben "Test: Failed", die WARNING-Stufe danach "Test: Warning" - beides, obwohl alle Tests fehlerfrei durchliefen.
- Zum Pruefen: In einem Testlauf (z. B. "odoo update --tests") duerfen im Log keine Tracebacks und keine WARNING-Zeilen aus zbsync-Modulen mehr auftauchen, sondern nur einzeilige INFO-Meldungen mit der Exception in Klammern. Die Instanz-Zaehler auf dem Pipeline-Formular (Erfolgreich / Laufend / Wartend) muessen weiterhin die richtigen Zahlen zeigen.
2026-08-07
zbsync_uibinding 1.2 → 1.3
- zSYNC UI buttons can now also be placed in the "Action" (cog) menu. -
- On the button (zSYNC pipeline -> UI Button) there is a new group
- "Placement" with two checkboxes: "Button in Views" (the previous
- behaviour, still on by default) and "Entry in Action Menu". With the
- second one enabled and "Update" pressed, the pipeline can be started
- from the Action menu of every list/form of the chosen model - no view
- selection needed. Select via "Show Menu Entry In" whether the entry
- appears in lists, forms or both. -
- Note for testers: states/attrs invisible only affect the header button.
- To hide the menu entry from certain users, use "Restrict Menu Entry To
- Groups"; record dependent checks belong into the pre-flight check, which
- is executed for the menu entry as well. Without groups Odoo only lets
- users run the menu entry if they may write the record. Multi selection in the list works
- like with the header button (one pipeline per record, or a single one
- with all records when batch mode is on).
2026-08-03
intellisense 1.0 → 1.1
- Neues Basis-Modul "intellisense": IDE-artige Autovervollständigung für
- Textfelder/Textareas plus eine erweiterbare Wort-Quelle. -
- Was testen / wo klicken:
-
- In einem Textfeld mit Widget
intellisense:
- In einem Textfeld mit Widget
<präfix>+ Tab zeigt alle passenden Wörter, Tab ohne Präfix- öffnet die komplette Liste. Wortquelle = Wörter im Feld + programmierbare
- Wörter. -
- Für Entwickler (Erweiterung):
-
- Statisch:
intellisense.word-Records anlegen.
- Statisch:
-
- Dynamisch (Backend): Modell erbt
intellisense.provider.mixinund
- Dynamisch (Backend): Modell erbt
- überschreibt
_get_intellisense_words(context). -
- Frontend: Provider in der JS-Registry
intellisense_word_providers
- Frontend: Provider in der JS-Registry
- registrieren. Aggregation über den Controller
/intellisense/words. - Basis-Mechanismus für Member-Vervollständigung (
objekt.<Tab>): steht der - Cursor hinter einem Punkt, fragt das Feld jetzt die Member des Objekts links
- des Punkts ab statt der globalen Wortliste. -
- Für Entwickler (Erweiterung):
-
- Neue Route
/intellisense/members(Parambase) bzw.
- Neue Route
intellisense.word._collect_members(model, field, base).-
- Provider implementieren
_get_intellisense_members(context)(context mit
- Provider implementieren
- zusätzlichem
base) aufintellisense.provider.mixinund liefern dieselben {word, description, category}-Einträge wie bei den Wörtern. Ein nicht- erkanntes
basegibt[]zurück (dann erscheint kein Vorschlag). -
- Frontend:
collectMembers(ctx)inproviders.js; dasintellisense-Textfeld
- Frontend:
- erkennt
base.memberam Cursor automatisch. - - Hinweis: Das Basis-Modul liefert selbst keine Member (generischer Mechanismus);
- die konkrete Auflösung kommt aus den jeweiligen Providern.
zbsync_files 1.4 → 1.5
- Intellisense in den Pfad-Feldern des File-Grabbers und File-Dumpers. -
- Was testen / wo klicken:
-
- File-Grabber öffnen, Reiter Path → Feld Filepath; sowie Reiter
- Action After Read → Destination Path (sichtbar bei "move").
-
- File-Dumper → Feld Filepath.
-
- Buchstaben tippen + Tab (oder leeres Tab) → Vorschläge mit den im
- Ausdruck verfügbaren Variablen (
record,data,input,index) plus - den Worker-Globals/Libs. Hinter einem Punkt Member (z. B.
record.<Tab>). - - Hintergrund:
zbsync_fileshängt dafür neu vonzbsync_intellisenseab; die - Felder nutzen
widget="intellisense".
zbsync_ftp 1.5 → 1.6
- Intellisense in den Pfad-Feldern des FTP-Grabbers und FTP-Dumpers. -
- Was testen / wo klicken:
-
- FTP-Grabber → Feld Filepath und Destination Path (sichtbar bei
- gesetztem "Action After Read").
-
- FTP-Dumper → Feld Filepath.
-
- Buchstaben tippen + Tab (oder leeres Tab) → Vorschläge mit
record,
- Buchstaben tippen + Tab (oder leeres Tab) → Vorschläge mit
data,input,indexplus Worker-Globals/Libs; hinter einem Punkt die- Member (z. B.
record.<Tab>).
zbsync_intellisense 1.0 → 1.1
- Korrekte Variablen-Vorschläge in den Web-Worker-Feldern und Unterstützung
- für non-Python-Codefelder (SQL-Grabber). -
- Was testen / wo klicken:
-
- Web-Worker → Feld Path bzw. Body: die Vorschläge enthalten jetzt die
- tatsächlich verfügbaren Namen
record,data,input,index(vorher - wurde fälschlich
urlvorgeschlagen, das dort gar nicht existiert). -
- Web-Worker → Extract Path: nur noch
response(keinurl).
- Web-Worker → Extract Path: nur noch
-
- Neuer Mechanismus, damit auch ACE-Felder ohne Python-Mode Intellisense
- bekommen können (genutzt vom SQL-Grabber in
zbsync_sql). - Member-Vervollständigung (
objekt.<Tab>) in den Python-Worker-Codefeldern: - hinter einem Punkt werden jetzt die Member des Objekts vorgeschlagen statt
- der globalen Wortliste. -
- Was testen / wo klicken:
-
- In einem Python-Codefeld (z. B. Transformer (Python) → "code") oben
import jsonschreiben.-
- In einer neuen Zeile
json.tippen und Tab drücken (auch ohne
- In einer neuen Zeile
- Buchstaben hinter dem Punkt). Es erscheint eine Box mit den Funktionen des
- Moduls (
dumps,loads,load,dump…) inkl. Kurzbeschreibung aus dem - Docstring.
-
json.du+ Tab filtert direkt aufdumps/dump.
-
- Worauf achten:
-
- Funktioniert auch für die Worker-Libs (
datetime.,base64.,uuid.,
- Funktioniert auch für die Worker-Libs (
Path.) und verkettet (datetime.date.).-
instance./instance_line.schlagen die Felder des jeweiligen
- Modells vor (Beschreibung = Feld-Label + Typ).
-
- Vorschläge stammen aus echter Python-Introspection im Backend, sind also
- exakt die zur Laufzeit verfügbaren Funktionen/Attribute. Importiert wird
- ausschließlich aus der Standardbibliothek.
- Intellisense / Autovervollständigung in den Python-Worker-Codefeldern. -
- Was testen / wo klicken:
-
- Ein Pipeline-/Worker-Codefeld mit Python öffnen, z. B.:
- Transformer (Python) → Feld "code", Mapper → "code" / "format_value" /
- "skip_record_expr", Web-Worker → "code_next_page" / "body" / "extract_path",
- Pipeline-Line → "condition" / "path_content" / "keep_input_filter".
-
- Im Code ein paar Buchstaben tippen und Tab drücken (oder Ctrl-Space).
- Es erscheint eine Vorschlagsliste direkt am Cursor.
-
- Worauf achten:
-
- Vorgeschlagen werden die im Worker verfügbaren Objekte/Libs, u. a.
env,record,instance,instance_env,vars,log,SkipRecord,ZBSPipelineExceptionsowiedatetime,arrow,base64,Path,uuid…-
- Zusätzlich werden Wörter aus dem aktuellen Code und selbst geschriebene
import/from … import …-Namen vorgeschlagen.-
- Navigation mit Pfeil hoch/runter, Übernahme mit Enter/Tab/Klick,
- schließen mit Esc.
-
- Bei genau einem Treffer wird direkt vervollständigt.
-
- Steht der Cursor nicht hinter einem Wort, rückt Tab wie gewohnt ein.
-
- Die Liste der Worker-Objekte/Libs kommt zentral aus dem Backend
- (Provider
zbs.intellisense.provider, gespeist aus den Default-Objekten - der Pipeline-Ausführung), ist also eine einzige Quelle der Wahrheit.
- In den Python-Codefeldern öffnet Tab jetzt auch ohne getipptes Wort die
- Vorschlagsliste. -
- Was testen / wo klicken:
-
- In einem Python-Codefeld (z. B. Web-Worker → "body", Transformer (Python)
- → "code") mitten in einer Zeile (z. B. nach einem Leerzeichen oder hinter
- einer offenen Klammer) Tab drücken: es erscheint die komplette
- Vorschlagsliste – vorher musste man dafür Ctrl-Space nehmen.
-
- Worauf achten:
-
- Steht der Cursor noch in der Einrückung am Zeilenanfang (nur
- Leerzeichen/Tabs davor), rückt Tab wie gewohnt ein – Python-Einrückung
- und das Einrücken markierter Blöcke funktionieren weiterhin.
-
- Mit Präfix filtert Tab wie bisher, hinter einem Punkt zeigt es die Member.
- Weitere Ausdrucks-/Pfad-Felder bekommen Intellisense-Kontext und der
- String-Builder wird angebunden. -
-
- Kontext-Variablen (
record,data,input,index) für die Pfad-Felder
- Kontext-Variablen (
- der File-/FTP-/WebDAV-Grabber und -Dumper (filepath, destination_path,
- local_path).
-
- String-Builder → Felder Header und Footer bekommen Intellisense
- (über ein View-Override hier, damit das Core-Modul
zbsyncnicht von den - Intellisense-Modulen abhängen muss).
- Intellisense für „Plain SQL" (ohne-Globals-Modus) und für post_process. -
- Was testen / wo klicken:
-
- SQL-Dumper / Plain-SQL → Feld Plain SQL: Tab zeigt nur die real
- verfügbaren Variablen
record,data,input– bewusst KEINE Worker- - Globals/Libs (env, instance, datetime …), weil dieses Feld ohne sie
- ausgewertet wird (sonst NameError zur Laufzeit). Member-Vorschläge
- (
x.<Tab>) sind hier deshalb ebenfalls aus. -
- post_process (z. B. Web-Worker → Feld „post_process"): bietet jetzt den
- vollständigen Kontext
record,data,input,index(vorher nur die - Default-Namen
record,data). - - Technisch: neuer „context-only"-Modus im Provider (CONTEXT_ONLY_FIELDS) für
- Felder, die via _exec_get_result ohne _get_default_objects laufen.
- Intellisense-Kontext für die WebDAV-Grabber-Felder Content Path und Glob. -
- Was testen / wo klicken:
-
- WebDAV-Grabber → Felder Content Path und Path Expression Glob: Tab
- bietet
record,data,input,indexplus die Worker-Globals/Libs - (env, instance, datetime …) an. -
- Technisch: CONTEXT_BY_FIELD-Einträge für (zbs.grabber.webdav, content_path)
- und (zbs.grabber.webdav, glob).
zbsync_sql 1.3 → 1.4
- Intellisense/Autovervollständigung im SQL-Daten-Grabber. -
- Was testen / wo klicken:
-
- SQL-Grabber öffnen (Menü zSYNC → SQL → Grabber).
-
- Im SQL-Feld ein paar Buchstaben tippen und Tab drücken (oder leeres
- Tab mitten in der Zeile): es erscheinen die im Worker verfügbaren Variablen
- (
record,data,indexsowieenv,instance,instance_env,vars, datetime,arrow…). Hinter einem Punkt werden die Member angeboten- (z. B.
datetime.<Tab>). -
- In der Domains-Liste im Feld Domain ebenso (Kontext
record,
- In der Domains-Liste im Feld Domain ebenso (Kontext
data+ die Worker-Globals/Libs).-
- Worauf achten: Am Zeilenanfang/in der Einrückung rückt Tab weiterhin ein. -
- Hintergrund:
zbsync_sqlhängt dafür neu vonzbsync_intellisenseab; das - SQL-Feld (ACE im SQL-Mode) wird über eine Allow-Liste für den Completer
- freigeschaltet, das Domain-Feld nutzt
widget="intellisense". - Intellisense im Feld Plain SQL des SQL-Dumpers. -
- Was testen / wo klicken:
-
- SQL-Dumper öffnen → Feld Plain SQL: Buchstaben tippen + Tab (oder
- leeres Tab) → Vorschläge
record,data,input. Bewusst ohne die - Worker-Globals/Libs, da das Feld ohne diese ausgewertet wird.
zbsync_web 1.4 → 1.5
- Das Feld Path im Web-Worker hat jetzt Intellisense/Autovervollständigung. -
- Was testen / wo klicken:
-
- Web-Worker öffnen (Menü zSYNC → Web-Worker), ins Feld Path klicken.
-
- Buchstaben tippen und Tab drücken (oder leeres Tab) → Vorschlagsliste
- mit den im Path verfügbaren Namen (u. a.
record,url) sowie den - Worker-Globals/Libs. Hinter einem Punkt werden die Member vorgeschlagen
- (z. B.
record.<Tab>). -
- Hintergrund: Das Feld nutzt jetzt
widget="intellisense"; dafür hängt
- Hintergrund: Das Feld nutzt jetzt
zbsync_webneu vonzbsync_intellisenseab.
zbsync_webdav 1.2 → 1.3
- WebDAV-Grabber: Content Path und Glob werden jetzt als Ausdruck ausgewertet
- (wie schon Local Path) und haben Intellisense. -
- Was testen / wo klicken:
-
- WebDAV-Grabber öffnen → Felder Content Path und **Path Expression
- Glob**: Buchstaben tippen + **Tab** (oder leeres Tab) → Vorschläge inkl.
record,data,input,indexsowie der Worker-Globals/Libs.-
- Beide Felder dürfen jetzt Ausdrücke enthalten (z. B. Pfad/Glob abhängig vom
- aktuellen Record); ein reiner Text-Pfad funktioniert weiterhin unverändert. -
- Technisch: content_path und glob laufen jetzt durch _eval_expression(index,
- record, data, input, expects_string_if_oneline=True). Leerer Glob fällt auf
- "*" zurück.
- Intellisense im Pfad-Feld des WebDAV-Grabbers. -
- Was testen / wo klicken:
-
- WebDAV-Grabber → Feld Local Path: Buchstaben tippen + Tab (oder
- leeres Tab) → Vorschläge mit
record,data,input,indexplus - Worker-Globals/Libs; hinter einem Punkt die Member.
-
- Hinweis: Content Path (entfernter Pfad) und Glob werden roh
- verwendet (nicht als Ausdruck ausgewertet), daher dort bewusst kein
- Variablen-Intellisense. -
- Hintergrund:
zbsync_webdavhängt dafür neu vonzbsync_intellisenseab.
2026-07-29
zbsync 2.1 → 2.2
- Horizontale Radiobuttons sind wieder normal lesbar. Das CSS fuer die
- Pill-/Segmented-Control-Optik (zbsync/static/src/css/pill_container.css) liegt
- im Backend-Asset-Bundle und galt bisher fuer JEDES Radio-Feld in Odoo, nicht
- nur fuer die Pills. Mit
padding: 0auf.o_radio_itemfiel das - padding-left der Bootstrap-Klasse
form-checkweg - Odoo rendert horizontale - Radiobuttons immer als
<div class="form-check o_radio_item">, deshalb rutschte - der Auswahlkreis mitten ins Label. -
- Zum Nachpruefen: einen Kontakt oeffnen (Verkauf oder Kontakte -> Neu). Die
- Auswahl "Einzelperson / Unternehmen" muss saubere Abstaende haben, Kreis links,
- Text rechts daneben - kein Kreis, der im Wort liegt. Das galt genauso fuer alle
- anderen horizontalen Radio-Felder, z.B. im Rechnungs- oder Lieferassistenten. -
- Zusaetzlich wurde eine zweite ungescopte Regel eingegrenzt, die den unteren
- Abstand von allen Formular-Labels in Gruppen auf 0 gesetzt hat. Beides gilt
- jetzt nur noch innerhalb von
.o_segmented_control, die Pill-Optik selbst - bleibt unveraendert.
zbsync_mapper 2.1 → 2.2
- Mapper-Vorschau (
mapping_json) sprengte bei großen/gestreamten - Pipeline-Ausgaben den Speicher. Das Feld wird über einen
@api.constrains("output_data")bei JEDEM Batch-Write neu berechnet und- serialisierte bisher die KOMPLETTE Batch-Ausgabe per
json.dumps. Bei - JSONL-Attachment-gestreamten Ausgaben (z.B. SQL-/Web-Streaming-Grabber mit
- Millionen Zeilen) materialisierte das den gesamten Datensatz in einen
- einzigen String — der Worker wuchs auf viele GB RAM und wurde in CI per
- OOM/Worker-Recycle mitten im Batch abgeschossen. Der Batch blieb dann in
processinghängen, die Pipeline wurde nie fertig (u.a. Ursache dafür, dasstest_bigdata_limitsDB-/Web-Szenarien nie grün wurden). -- Für die Mapper-Vorschau genügt EIN repräsentativer Beispiel-Datensatz (zur
- Auflösung der Feld-Mappings) — genau wie es für Listen-Ausgaben ohnehin
- schon gemacht wurde (
formatted[0]). Streaming-Ausgaben werden jetzt - ebenso behandelt: es wird nur der erste Record lazy aus dem JSONL-Stream
- gelesen, statt den ganzen Stream zu serialisieren. Der Speicher bleibt damit
- konstant, unabhängig von der Datenmenge. -
- Tester-Sicht (zSYNC → Pipeline mit Mapper): Bei Pipelines mit sehr großen
- Quellen (Streaming-Grabber) läuft die Verarbeitung jetzt speicherstabil
- durch; die Mapper-Vorschau zeigt weiterhin einen Beispiel-Datensatz.
web_diffview 1.1 → 1.2
- On instances where the old module "web_diffview" was installed, the server
- logged an error on every start and every update, because the module had been
- dropped from the code while the database still had it flagged as installed: -
- Some modules are not loaded, some dependencies or manifest may be missing: [web_diffview]
- Model mixin.diffview is declared but cannot be loaded! -
- Odoo cannot uninstall a module whose code is gone, so the leftover entry could
- not be cleaned up from the Apps list either. -
- "web_diffview" is shipped again as an empty module (no models, no views, no
- assets) and is marked for uninstallation in MANIFEST, so the next update
- removes it by itself - nothing to click. -
- How to test: update an instance that had web_diffview installed. Afterwards the
- two log lines above are gone, and under Apps (remove the "Apps" filter, search
- for "web_diffview") the module shows up as not installed. On instances that
- never had it, nothing changes - the module stays uninstalled.
zbsync 2.0 → 2.1
- Doppelte Felddefinitionen am Batch entfernt, Log beim Installieren wieder sauber. -
- Im Batch-Modell (zbs.instance.line.batch) waren input_data, output_data,
- processed_records und done_tries versehentlich zweimal definiert. Die zweite,
- knappere Definition hat die dokumentierte ueberschrieben und done_tries mit
- tracking=True versehen - das Modell hat aber kein Chatter, deshalb hat Odoo
- beim Laden gewarnt. Die Duplikate sind weg, die Hilfetexte an den Feldern
- bleiben erhalten. -
- Zusaetzlich drei Meldungen aus der View-Pruefung behoben: der Instances-Button
- im Pipeline-Dashboard hat jetzt role="button", das Zahnrad in der
- Schritt-Liste der Pipeline-Instanz einen Tooltip ("Open this step"), und die
- Transformer-Form nutzt hasclass() statt @class. -
- Zum Testen: Instanz frisch installieren bzw. updaten und das Update-Log
- ansehen - zu zbs.instance.line.batch darf keine Warnung mehr auftauchen.
- In der Pipeline-Instanz beim Zahnrad in der Schritt-Liste erscheint nun ein
- Hinweistext, funktional aendert sich nichts.
zbsync_ftp 1.4 → 1.5
- Modulbeschreibung im Manifest hinterlegt. -
- Ohne eigene Beschreibung hat Odoo die README.md als reStructuredText
- interpretiert und beim Installieren Formatierungsfehler ins Log geschrieben.
- Das Manifest enthaelt jetzt eine kurze Beschreibung; die README.md bleibt
- unveraendert Markdown (inkl. der Docker-Befehle fuer den Test-FTP-Server). -
- Zum Testen: Modul installieren und das Update-Log ansehen - keine
- Formatierungsmeldungen mehr. In Apps zeigt das Modul jetzt einen kurzen
- Beschreibungstext.
zbsync_mapper 2.0 → 2.1
- Warnungen beim Installieren entfernt (Backend-Kategorie, Feldbezeichnungen). -
- Am Feld parent_path der Mapper-Backend-Kategorie stand der Parameter
- unaccent, den Odoo 19 nicht mehr kennt - er ist entfernt. -
- Ausserdem hatten im Mapping jeweils zwei Felder die gleiche Bezeichnung
- ("Parent Path" bzw. "Source Field"), was Odoo beim Laden bemaengelt. Die
- technischen Bezeichnungen sind jetzt eindeutig ("Parent Store Path" bzw.
- "Source Backend Field"); in den Ansichten steht unveraendert das gleiche
- Label wie vorher. Die berechneten Felder parent_source_field_id und
- parent_dest_field_id sind als recursive markiert, weil sie sich ueber die
- Eltern-Mappings selbst auswerten. -
- Zum Testen: Mapper oeffnen, Quell-/Zielfeld-Auswahl und die Spalte "Parent"
- pruefen - Beschriftungen und Verhalten sind unveraendert. Beim
- Suchen/Gruppieren bzw. im Export heissen die technischen Felder jetzt anders.
zbsync_marketplace 1.6 → 1.7
- Version-Feld im Marketplace-Assistenten eindeutig bezeichnet. -
- Im Assistenten "New Pipeline from Marketplace" hiessen zwei Felder "Version".
- Das berechnete Feld heisst technisch jetzt "Latest Version"; im Formular
- steht unter "Latest Version" weiterhin die Beschriftung "Version". -
- Zum Testen: Marketplace-Pipeline anlegen - der Block "Latest Version" sieht
- aus wie vorher.
zbsync_marketplace_transformer_helper 1.1 → 1.2
- Fehlende Modellbeschreibung ergaenzt. -
- Der Upload-Assistent (zbs.marketplace.helper.upload) hatte keine
- _description, worauf Odoo beim Laden hingewiesen hat. -
- Zum Testen: Helper in den Marketplace hochladen - der Assistent verhaelt sich
- unveraendert.
zbsync_odoo 2.0 → 2.1
- Eindeutige Feldbezeichnungen und Umstieg von odoo.osv. -
- Am Odoo-Grabber/-Dumper hiessen Model (Text, externe Verbindung) und Model
- (Auswahlfeld, lokale Verbindung) beide gleich - Odoo hat das beim Laden
- bemaengelt. Das Textfeld heisst technisch jetzt "Model (Technical Name)", in
- den Formularen steht weiterhin "Model" an beiden Stellen. -
- Der Import von odoo.osv (in Odoo 19 als veraltet gemeldet) ist raus; die
- Domain wird jetzt direkt zusammengesetzt, was fuer XML-RPC ohnehin
- erforderlich ist. -
- Zum Testen: Odoo-Grabber und -Dumper mit lokaler und mit externer Verbindung
- oeffnen - je nach Verbindung erscheint wie bisher das Auswahlfeld oder das
- Textfeld, beschriftet mit "Model". Einen Dumper mit ___keys und
- zusaetzlicher Domain laufen lassen und pruefen, dass die Datensaetze wie
- vorher gefunden werden.
zbsync_odoo_mapper 2.0 → 2.1
- Eindeutige Bezeichnung fuer das gemappte Modell. -
- Das Feld model_external_id hiess wie die beiden Model-Felder aus
- zbsync_odoo, worauf Odoo beim Laden hingewiesen hat. Technisch heisst es
- jetzt "Model (Backend)", im Formular steht unveraendert "Model". -
- Zum Testen: Odoo-Grabber/-Dumper mit externer Verbindung oeffnen, Modell aus
- der Liste der synchronisierten Modelle waehlen - Beschriftung und Verhalten
- wie bisher.
zbsync_pipeline_widget 2.2 → 2.3
- Route auf jsonrpc umgestellt. -
- Der Endpoint /zync/change_sequence war noch mit type="json" registriert, was
- Odoo 19 als veralteten Alias meldet. Er nutzt jetzt type="jsonrpc". -
- Zum Testen: Pipeline-Widget oeffnen und Schritte per Drag & Drop umsortieren.
zbsync_receiver 1.1 → 1.2
- Leserechte am Authorizer auf interne Benutzer eingeschraenkt. -
- Die Zugriffsregel fuer den Receive-Authorizer war ohne Gruppe hinterlegt,
- galt also fuer jeden - Odoo weist beim Installieren darauf hin, dass Regeln
- ohne Gruppe veraltet sind. Das Leserecht haengt jetzt an "Interner Benutzer";
- die Vollrechte fuer die zSYNC-Manager bleiben unveraendert. Die oeffentlichen
- Receiver-Endpoints lesen den Authorizer ohnehin mit erhoehten Rechten, an der
- Funktion aendert sich nichts. -
- Zum Testen: Receiver-Pipeline mit Authorizer aufrufen (auch die
- JWT-Anmeldung) - Anmeldung und Verarbeitung laufen wie bisher. Als normaler
- interner Benutzer ist der Authorizer weiterhin lesbar, als Manager
- bearbeitbar.
zbsync_specification 1.0 → 1.1
- Umstieg von odoo.osv auf direkte Domain-Verknuepfung. -
- Der Import von odoo.osv wird in Odoo 19 als veraltet gemeldet. Die
- Query-Parameter-Domain wird jetzt ohne diesen Import zusammengesetzt, das
- Ergebnis ist identisch. -
- Zum Testen: REST-Konfiguration mit Query-Parametern aufrufen und pruefen,
- dass wie bisher genau die passenden Datensaetze geliefert werden.
zbsync_trigger_methods 1.3 → 1.4
- Tooltip am Hilfe-Symbol im Pipeline-Formular. -
- Die beiden Fragezeichen-Symbole neben den Trigger-Listen hatten keinen
- Titel, was Odoo bei der View-Pruefung bemaengelt hat. Sie zeigen jetzt
- "Open the documentation" als Tooltip. -
- Zum Testen: Pipeline oeffnen, Reiter mit Methoden-/Feld-Triggern - beim
- Ueberfahren des Fragezeichens erscheint ein Hinweistext, der Link fuehrt
- weiterhin in die Dokumentation.
zbsync_xport 1.5 → 1.6
- Modulbeschreibung im Manifest hinterlegt. -
- Ohne eigene Beschreibung hat Odoo die README.md als reStructuredText
- interpretiert und beim Installieren Formatierungsfehler ins Log geschrieben.
- Das Manifest enthaelt jetzt eine kurze Beschreibung; die README.md bleibt
- unveraendert Markdown. -
- Zum Testen: Modul installieren und das Update-Log ansehen - keine
- Formatierungsmeldungen mehr. In Apps zeigt das Modul jetzt einen kurzen
- Beschreibungstext.
zbsync_xport_ui 1.8 → 1.9
- Downloading a pipeline failed with a server error when its name contained a
- "/" (e.g. "Customer/Import"): the name went unfiltered into the export
- filename, where the slash was treated as a subdirectory. -
- How to test: create a pipeline with a "/" in its name, tick it in the list
- view and export it via Action -> Download, and also via the XML download on
- the pipeline form. Both now return a file. In the filename, "/" and similar
- special characters are replaced by "_"; the pipeline name itself is unchanged.
2026-07-28
zbsync 1.13 → 2.0
- Heimruf (call_home) sendet weniger personenbezogene Daten (DSGVO). -
- Der tägliche call_home-Ping an das Zebroo-Backend übermittelt jetzt nur
- noch die zur Zuordnung und Abrechnung nötigen Angaben: die database_uuid,
- die Firmennamen und die Nutzungszahlen (Pipelines, Mappings). -
- Die bisher zusätzlich gesendeten Adressdaten (Straße, PLZ, Ort je Firma)
- werden NICHT mehr übertragen. Funktional ändert sich für den Anwender
- nichts; die Datenübermittlung ist datensparsamer.
- Error display, popover pagination, domain expressions, and pipeline UX. -
- Error display
-
- err_desc_display: new computed HTML field that renders structured error
- data (message, record, traceback) as formatted HTML in the UI.
-
- ExceptionFormatter hardened: extracts args[0] directly, stores record
- as None, joins traceback lines into a string. -
- Popover pagination
-
- Large input/output/error text is paginated in 250-line pages with a
- 1 000-character-per-line cap; new get_batch_field_page() and
- get_popover_field() methods on Batch and InstanceLine.
-
- New ZbsPagedTextField JS component with batch navigation, inline range
- editing, and improved fixed positioning (bottom anchor, 10 vh top). -
- Domain expressions
-
- _resolve_dynamic_values() evaluates $-prefixed runtime expressions in
- domain tuples ($record.name, $uid, $data.get('x')).
-
- domain field now defaults to "[]" and is no longer required. -
- Pipeline UX
-
- blocked_by_step_mode field shows a warning alert and ribbon when another
- instance is running in step-by-step mode.
-
- Tree view decorations for paused and blocked pipeline instances.
-
- Disabled workers shown as muted/greyed out in list views.
-
- Heartbeat interval slowed from 10 seconds to 1 minute. -
- Misc
-
- uid added to default execution objects.
-
- propagate_toggle.js/xml: new boolean field widget.
-
- Post-init hook backfills UTF-8 encoding xmlid aliases
- (encoding_utf-8, encoding_utf8 → encoding_utf_8).
-
- Removed privilege_id from manager group.
- Zwei Regressionen aus dem Streaming-/Cursor-Reduction-Umbau behoben, die
- die Testsuite auf 19.0 rot gemacht haben. -
-
- Resume-Cursor + Idempotency-Token griffen im echten Batch-Lauf gar nicht.
- Der Worker-Loop liest den Batch aus
context['zbs_current_batch_id'], - aber
zbs.instance.line.batch._exec_runhat nurzbs_batch_idgesetzt - (anderer Key). Folge: der Cursor
processed_input_indexwurde nie - fortgeschrieben und
context['zbs_idempotency_token']war fuer jeden - Record None.
_exec_runsetzt jetzt zusaetzlichzbs_current_batch_id. - - Tester-Sicht (Backend, Tech-View eines
zbs.instance.line.batch): - Nach einem Lauf steht "Processed Input Index" korrekt auf der Anzahl
- verarbeiteter Records; crasht ein Worker mittendrin und laeuft erneut,
- ueberspringt er die bereits erledigten Records statt alles zu wiederholen. -
-
- Attribut-Zugriff auf ein Streaming-Ergebnis (z.B.
data.Namenach einem
- Attribut-Zugriff auf ein Streaming-Ergebnis (z.B.
- CSV-Grabber, dessen Output als JSONL-Attachment gestreamt wird) warf
AttributeError.ZebrooSet-Dive kollabierte ein Ein-Record-Ergebnis- nur fuer echte Listen, nicht fuer den lazy
JsonlAttachmentIterator. - Dive behandelt einen Ein-Record-Stream jetzt wie eine 1-Element-Liste. -
- Tester-Sicht: CSV-Import (Grabber) liefert die Felder wieder korrekt —
Name/Street/Citysind ueber das Ergebnis erreichbar, auch bei- Streaming-Ausgabe. Betrifft alle Streaming-Grabber (CSV, SQL, Web, XML). -
- Coverage: gruen sind wieder
zbsync/tests/test_batch_resume.py(8 Tests, - die den Worker real ausfuehren) und
zbsync_excel_csv/tests/test_csvexcel.py - (CSV-Import).
- Big-Data-Streaming-Testsuite (
tests/suites/test_bigdata_limits) so - dimensioniert, dass sie in CI durchlaeuft. Bisher erzeugte die Suite per
- Default 25 Mio. Zeilen (~18 GB CSV / ~30 GB XML) und lief damit ~2,3 h pro
- Lauf -> der Robotests-Job lief in sein 140-Minuten-Timeout und wurde als
- "cancelled" gewertet. Die Suite war deshalb seit ihrer Einfuehrung nie gruen. -
- Der Standard-Umfang liegt jetzt bei 1 Mio. Zeilen. Das streamt weiterhin
- ueber mehrere Chunks, haelt den Speicher nachweislich konstant und pruefen
- weiterhin CSV/XML/DB/Web end-to-end, ist aber in wenigen Minuten fertig. Der
- volle 25-Mio-Zeilen-Stresstest bleibt erhalten und wird explizit angestossen:
- BIGDATA_ROWS=25000000 odoo robot run test_bigdata_limits
- bzw.
- odoo robot run test_bigdata_limits -p BIGDATA_ROWS=25000000 -
- Hintergrund: Die gemeinsame Robotests-Workflow (
robotests.yml) kann weder -pnoch zusaetzliche Env-Variablen in den Robot-Container reichen, deshalb- muss der CI-Umfang im Default der Generatoren liegen, nicht im CI-Aufruf. -
- Tester-Sicht (zSYNC -> Robot-Tests):
test_bigdata_limitslaeuft in CI - jetzt in Minuten auf gruen durch. Wer die echten Grenzen testen will, setzt
BIGDATA_ROWShoch.- Fix TypeError in zbs.environment._import() when a JSON variable has a
- non-list value (e.g. boolean True): use isinstance check instead of
values or []which returns True for truthy booleans.- In-Order-Ausfuehrung von Pipeline-Schritten repariert
- (
batch_execution_in_order). Eine Pipeline mit einem so konfigurierten - Schritt blieb haengen und warf beim manuellen "Go" einen Fehler. -
zbs.instance.line.batch.retry_if_batch_execution_in_orderhatte zwei- Fehler:
-
- Sie verlangte ein Argument
instance_line_id, das der einzige Aufrufer nie
- Sie verlangte ein Argument
- uebergab und der Rumpf nie nutzte ->
- "missing 1 required positional argument: 'instance_line_id'" beim Retry.
-
- Die Wartebedingung verglich das
exists(...)-Bool mitself.id
- Die Wartebedingung verglich das
- (
next_batch[0] != self.id) und war damit auch dann wahr, wenn KEINE - fruehere Batch offen war -> die erste Batch wartete endlos, die Pipeline kam
- nie weiter ("haengt im n-ten Step"). -
- Beide behoben: das ueberfluessige Argument ist entfernt, die Bedingung
- prueft jetzt korrekt, ob eine fruehere
todo/processing-Batch existiert. - - Tester-Sicht (zSYNC -> Pipeline mit einem Schritt, bei dem
- "Batch-Ausfuehrung der Reihe nach" aktiv ist): Die Pipeline laeuft die Steps
- in Reihenfolge durch, bleibt nicht stehen, und "Go"/Retry wirft keinen Fehler
- mehr. Batches desselben Steps werden weiterhin strikt in Reihenfolge
- abgearbeitet (eine Batch wartet, solange eine fruehere noch offen ist). -
- Coverage: neuer Unit-Test
zbsync/tests/test_batch_execution_in_order.py(5 Faelle).- Fix: Step-Reihenfolge nach Marketplace-Download stimmt wieder (ZO-05230).
- Beim Upload zum Marketplace werden die automatischen "Start"-/"Stop"-Schritte
- entfernt; beim Download wurden sie zwar neu angelegt, landeten aber beide am
- Ende der Pipeline – "Start" stand dadurch an vorletzter Stelle.
- Tester: Pipeline zum Marketplace hochladen, lokal löschen, Katalog updaten und
- wieder herunterladen. In der heruntergeladenen Pipeline muss "Start" jetzt
- ganz oben und "Stop" ganz unten stehen, die echten Schritte unverändert
- dazwischen.
- Weitere Regressionen aus dem Streaming-/Cursor-Reduction-Umbau behoben, die
- Streaming-Pipelines mit groesseren Datenmengen auf 19.0 rot gemacht haben. -
-
- Streaming-Ergebnis wurde an Nicht-Streaming-Code als EIN Pseudo-Record
- durchgereicht bzw. war nicht serialisierbar.
ZebrooSet.iterate_data - iteriert einen lazy Record-Stream (
JsonlAttachmentIterator) jetzt Record - fuer Record, statt den ganzen Stream als
[stream]zu yielden; und der - JSON-
Encoderkann einen solchen Stream serialisieren (materialisiert ihn - bewusst, z.B. im Fehler-Handler des Workers). -
- Tester-Sicht: Grabber mit gestreamter Ausgabe (CSV/SQL/Web/XML) laufen
- durch, ohne dass der naechste Step
AttributeErrorbzw. - "Object of type JsonlAttachmentIterator is not JSON serializable" wirft. -
-
- Serialization-Konflikt beim Verarbeiten grosser/gestreamter Batches. Der
- Batch-Worker laeuft in einem eigenen DB-Cursor (
new_env), der per Odoo- - Default REPEATABLE READ ist. Der Resume-Cursor-Update pro Record
- (
processed_input_index) und das Schreiben der Ergebnis-Zeile liefen so - gegen den Heartbeat-Thread (der
processing_sinceauf derselben - Batch-Zeile aktualisiert) und warfen "could not serialize access due to
- concurrent update" — systematisch bei grossen Dateien, weil das
- Attachment-Schreiben laenger als das 30s-Heartbeat-Intervall dauert. Der
- Worker-Cursor wird jetzt auf READ COMMITTED gesetzt (Konflikt blockiert
- kurz statt zu erroren); zusaetzlich wird ein solcher transienter Fehler in
- der Nachbearbeitung als retrybar behandelt statt als permanenter
- BatchFailed. -
- Tester-Sicht: Grosse CSV-/XML-/DB-/Web-Importe laufen auf "success" durch,
- statt mit einer einzelnen fehlgeschlagenen Batch haengenzubleiben. -
- Coverage: gruen ist wieder
tests/suites/test_bigdata_limits/test_bigdata_limits.robot - (CSV/XML/DB/Web) sowie die Streaming-Grabber-Suiten.
- Subpipeline-Aufruf ("Pipeline Trigger"-Worker) im echten Betrieb repariert —
- eine Regression aus dem Cursor-Reduction-Umbau, die auf 19.0 einen Runaway
- ausgeloest hat. -
- Der Worker
process()laeuft seit dem Umbau in einem eigenen DB-Cursor - (
new_env). Der Trigger merkt sich die gestartete Sub-Instanz in batch.started_sub_instance_id, committete diesen Write aber auf dem- falschen Cursor: die Sub-Instanz wurde persistiert, das Merkfeld auf der
- Batch-Zeile hing am aeusseren Cursor und wurde beim anschliessenden
- WaitHere-Retry zurueckgerollt. Folge: bei JEDEM Heartbeat sah der Trigger
- wieder ein leeres
started_sub_instance_idund startete eine weitere - Sub-Instanz -> unendlich viele "pending" Sub-Instanzen, die Hauptpipeline
- wurde nie fertig.
batch/workerwerden jetzt an den committenden Cursor - gebunden, sodass Write und Commit zusammenpassen. -
- Tester-Sicht (zSYNC -> Pipelines): Eine Pipeline mit einem "Pipeline
- Trigger"-Schritt, per Cronjob/Button gestartet, erzeugt jetzt GENAU EINE
- Sub-Instanz (zu sehen unter der Instanz -> Sub-Instanzen). Die Hauptpipeline
- wartet korrekt auf die Sub-Pipeline und laeuft danach auf "success" durch —
- in allen Modi (Fire and Forget, Wait Until Done, Return Data). Vorher blieb
- sie haengen und die Sub-Instanz-Liste lief voll. -
- Coverage: gruen ist wieder
tests/suites/test_pipelines/test_call_subpipeline.robot. - Heimruf (call_home) härtet die ausgehende Verbindung ab. -
- Der tägliche call_home-Cronjob (zbs.call_base._call_base) sendet die
- Nutzungs-Telemetrie jetzt mit einem Netzwerk-Timeout (30 s) und fängt
- Verbindungsfehler ab. Ist der Backend-Server (odoo.zebroo.de) nicht
- erreichbar, läuft der geplante Job nicht mehr auf Fehler ("rot"), sondern
- protokolliert nur eine Warnung im Log und endet sauber. -
- Zum Testen: Settings → Technical → Automation → Scheduled Actions →
- "zync:call_home" manuell ausführen; bei nicht erreichbarem Backend bleibt
- der Job grün und im Log erscheint "zSYNC call_home failed: ...".
- Odoo 19 compatibility and robustness fixes.
-
- zbs.worker: replaced the removed name_get() override with
- _compute_display_name (keeps the "deleted" fallback).
-
- _roll_after_start: fixed a NameError where the BatchFailed exception
- variable was referenced after its except block.
-
- default-environment migration is now idempotent (never creates a
- second default, which would break _get_default_env).
- Reduce memory footprint of the batch run loop:
-
- cache _get_data() result in _clearance_granted to skip the second
- json.loads/ZebrooSet decode when locks are identified
-
- flush input_data/output_data from the ORM cache after _log_process_result
- so prior batches don't linger in memory across a cron pass
-
- drop json indent=4 outside test_mode (env context zbs_test_mode); saves
- ~30% on serialized payload size for production runs
-
- cap exception formatter: traceback frames (5 head + 15 tail), zbs_record
- payload (16 KB), exception str (4 KB) — prevents secondary OOM when
- err_desc is built on a memory-saturated worker
- Eliminate extra pool cursors for lock coordination. -
- Replaced 9 pglock(...) advisory-lock sites that each opened a fresh
- connection via new_env(enabled=True) with three mechanisms that all
- use self.env.cr — zero extra cursor for locking: -
-
- Batch identity: atomic UPDATE state='todo'->'processing' state-machine
- on zbs.instance.line.batch. Watchdog cron (zbsync_reset_stale_batches)
- resets stale processing rows after zsync.batch.stale.timeout.sec
- (default 300s).
-
- Resource reservation: new model zbs.resource.lock with
- UNIQUE(resource_key) + ondelete=cascade. INSERT ON CONFLICT
- DO NOTHING for acquire; cascade-delete for release.
-
- Pipeline coordination (_make_batches, _goto_next_line,
- _make_and_queue_batches, _check_batchdone_continue,
- _reset_processed): SELECT ... FOR UPDATE row-lock on zbs_instance. -
- Motivation: "too many clients" errors on Odoo.sh and large
- deployments under parallel pipelines.
- Cut redundant pool-cursor opens in the batch run loop and on the
processed_recordscomputed field. -- Each batch run used to acquire up to 3 sequential advisory-lock
- cursors via
new_env(enabled=True)—pglock("batch_<i>/<b>")(kept), - plus
pglock("resoure_check_<line>"),pglock(locks)and pglock("exec_run_<batch>")(all redundant with each other for the- batch-id scope or coalescable). -
-
_exec_run: the innerpglock("exec_run_<batch>")is gone. The
- outer
batch_<i>/<b>lock fromheartbeat()plus the batch-id - lock inside
_clearance_granted()already serialise the same - scope.
-
_clearance_granted: the previous "acquire resource_check pglock
- → identify → release → acquire locks pglock" pattern now lives on
- a single
new_env. Two new helpers onzbs.tools, pg_advisory_acquire(name, wait=False, cr=None)andpg_advisory_release(name, cr=None), let callers coalesce- sequential advisory locks onto one extra connection instead of
- opening one per
pglock(...). -
_compute_counter(zbs.instance.line.batch + zbs.instance.line):
new_env()is gone in favour of reusing the main cursor withcursor_change_to_read_committed. The per-line N+1 loop on the- instance-line side collapses to a single LEFT JOIN. Computed
- fields no longer force an extra commit on every UI render. -
- Net effect: ~2-3 fewer cursor acquisitions per batch (still 1 for
- the outer batch lock + 1 for
_clearance_granted's locks + 1 for - the worker_env inside
_exec_run), andprocessed_recordsreads - stop hammering the pool entirely.
- Per-record resume-cursor on batches: a crashed worker now resumes at
- the next unprocessed input record instead of replaying the whole batch. -
- Tester-Sicht (developer/admin im Backend): -
-
- Auf
zbs.instance.line.batchgibt es das neue Feld
- Auf
- "Processed Input Index" (
processed_input_index). Es zeigt, bei - welchem 0-basierten Input-Record der Worker beim nächsten Run
- weitermacht. Sichtbar im Tech-View des Batch-Records.
-
- Wenn ein Worker bei Record 3 von 5 crasht (kill -9, OOM,
- RetryableJobError), bleibt
processed_input_index=3stehen. Der - Watchdog-Reset setzt den Batch nur von state='processing' auf 'todo'
- zurück — der Cursor wird NICHT genullt. Im erneuten Lauf überspringt
- der Worker Records 0–2 und beginnt bei Record 3. Records 0–2 sehen
- den Worker also nicht zweimal.
-
- "Reset & Play" /
_debug_play()setzt den Cursor explizit auf 0
- "Reset & Play" /
- (Developer will sauberen Re-Run, kein Resume).
-
heartbeat_ui()(User-Klick auf "wieder versuchen") behält den
- Cursor (Side-Effects nicht nochmal feuern).
-
- Beim
_make_batches-Rebuild (Pipeline neu losschicken) sind die
- Beim
- alten Batches per cascade-delete weg → neue Batches starten bei 0. -
- Worker-API: -
-
- Der Worker-Context führt jetzt pro Record einen stabilen
- Idempotency-Token:
context['zbs_idempotency_token']mit dem Format batch_<batch_id>_rec_<index>. Stable über alle Retries derselben- (Batch, Index)-Kombination.
-
- In
zbs.transformer(python-transformer) ist der Token zusätzlich
- In
- als
idempotency_tokenin den python-globals verfügbar, kann also - direkt im Worker-Snippet gelesen werden (z.B. als X-Idempotency-Key
- auf einem HTTP-POST oder als Dedup-Spalte beim DB-Insert).
-
context['zbs_record_index']ist der 0-basierte Index des aktuellen
- Records im Batch. -
- Semantik: -
-
- At-least-once: ein Crash exakt zwischen dem Side-Effect des Workers
- und dem Cursor-Commit kann diesen einen Record erneut feuern. Für
- nicht-idempotente Side-Effects nutzt der Worker den Token. Workers
- selbst werden mit diesem PR NICHT angepasst — der Token ist da,
- Worker können opt-in.
-
- Bei Streaming-Workern (Generator-Output) wird der Cursor schon im
- Outer-Loop pro Input-Record vorangezogen, nicht erst beim Verbrauch
- des Generators. Das hält "Cursor = Input wurde gelesen + verarbeitet"
- invariant; downstream-Consumer (dump_data) holt sich die Outputs
- weiterhin lazy via
_chain(). - - Coverage: 15 neue TransactionCase-Tests in
zbsync/tests/test_batch_resume.pydecken den Cursor durch Crashes,- Watchdog-Reset,
_debug_play,heartbeat_ui, RetryableJobError, - Streaming-Workers und konkurrenten Acquire ab.
- Code-review follow-ups on the streaming refactor: -
-
_clearance_granted: fix partial-acquire lock leak. The loop that
- pulls multiple advisory locks onto the shared
new_envnow tracks - each successful acquire in a
heldlist and releases only those in finally. A mid-loop contentionRetryableJobErrorno longer- leaves earlier locks dangling. -
-
stream_attachment_from_iter/stream_attachment_from_pathnow
- return
(attachment, true_size_bytes). The previous shape returned - just the attachment whose
file_sizefield is silently clamped to - int4 max (~2 GiB) — callers that pass the value downstream (file /
- FTP / web grabbers) now propagate the real byte count. -
-
pg_advisory_held(name, wait=False, cr=None): new contextmanager
- flavour of
pg_advisory_acquire. Single-lock callers should prefer - it so the release can't be forgotten. The plain
pg_advisory_acquirenow ships with a docstring warning explaining- that the lock is session-scoped (no auto-release on commit). -
-
iter_records(zbsync_sql) drops the unreachable tuple-row fallback;
- every supported driver returns dicts at this layer. -
-
JsonlAttachmentIterator.__getitem__docstring spells out the O(N)
- cost; downstream code that needs full iteration should call
_zbs_iterate_recordsdirectly. --
- bigfaker / bigxml emit a one-liner to stderr at the start of
- generation so the multi-minute CSV/XML write doesn't look like a
- hang.
zbs.grabber_dumpergets_open_record_stream(record, requires='str')- context manager: when the input record carries
_source_attachment_id - (PR 1's streaming emit), it opens the attachment file directly from the
- filestore — no
ir.attachment.rawread that loads the whole file into - RAM. Falls back to wrapping inline
contentin BytesIO/StringIO so - existing pipelines keep working. -
- Fixes the helper so the attachment record correctly references its
- streamed file: Odoo's
ir.attachment.createstripsstore_fname, file_size,checksumfrom create vals — we patch them via SQL- immediately after, then invalidate the cache.
- End-to-end streaming for source-grabber → parser → next worker pipelines.
- Pipeline output_data no longer materialises records as a single JSON blob
- in a Text column; instead workers that return a generator stream their
- records as JSONL into an ir.attachment, and the next stage reads them
- back line-by-line via a
JsonlAttachmentIterator. - - Changes:
-
zbs.attachment.helper.stream_jsonl_from_iter(): write a generator of
- records as JSONL through the existing chunked Filestore writer. Each
- record is encoded with ZebrooSet's Encoder so recordsets, datetimes and
- Decimals survive round-trips. Returns (attachment, row_count).
-
ir.attachment.file_sizeis a 32-bit Integer; the helper now clamps
- the value and stashes the true size in
descriptionfor files > 2 GiB. -
JsonlAttachmentIterator(new in zebrooset.py): lazy line-by-line
- iterator over a JSONL attachment. Implements
__iter__,__len__ - (cached row_count),
__bool__,__getitem__(integer-only, expensive), - and the existing
_zbs_iterate_recordshook so it slots into ZebrooSet - without changing the iteration API. Re-opens the file on every
- iteration so it can be consumed multiple times.
-
zbs.pipeline.line.dump_data/load_data: new marker
ZBS_JSONL:<att_id>:<row_count>for streaming payloads.dump_data- detects Python generators, JsonlAttachmentIterators, or ZebrooSets
- wrapping them, and routes through
_dump_jsonlwhich calls the helper. load_dataunpacks the marker into aJsonlAttachmentIteratorwrapped- in a ZebrooSet — the iterator only opens the file when actually
- iterated.
-
zbs.worker._process_worker_base: collects per-record worker outputs
- without losing laziness. If any
process_recordreturned a generator, - the whole worker output is chained through a single generator
- (
_chain()) so it flows straight intodump_dataand never - materialises in RAM.
-
zbs.instance.line._append_data: streaming-guard branch — when batch
- output sits behind a lazy iterator, the single-batch case passes
- through untouched instead of doing
container += itemwhich would - burn the records out. -
- Combined with PR 1+2, a 5M-row / 3.7 GB CSV now streams end-to-end
- through the pipeline in ~4 minutes under a 1 GB worker heap budget.
- Fast-path in
_dump_jsonl: when the data is already a JsonlAttachmentIteratorbacked by an existing filestore attachment,- re-emit the original marker
ZBS_JSONL:<id>:<rows>instead of reading - the file and writing a new one. Skips the per-record encode/decode pass
- on line transitions where no record actually changed (typically the
_make_batchesstep with batchsize=NULL between streaming workers). -- For a 25M-row / 18 GB CSV the line→line transition used to rewrite a
- 29 GB JSONL — now it's a no-op. End-to-end run time drops from
- ~14 min (test timed out) to 10.6 min (test passes). -
- Side-fix:
_log_process_resultnow propagateszbs_current_batch_id - into the env that calls
dump_data, so streaming JSONL attachments - produced during worker output get tied to the current batch
- (cascade cleanup via
keep_instances_for_days) instead of being - orphaned in the filestore.
- New abstract helper
zbs.attachment.helperthat streams arbitrary byte - sources into an ir.attachment without holding the full payload in RAM:
- chunks are appended to a temp file in the filestore, sha1 is computed on
- the fly, then the file is atomically moved into the canonical
<sha>[:2]/<sha>layout and an ir.attachment record is created withstore_fnameset directly. -- Source-grabbers can now emit
_source_attachment_idin their output - records when input exceeds
zsync.streaming_threshold_bytes(default - 10 MB) and a batch context is available. The attachment is tied to the
- current batch via
res_model='zbs.instance.line.batch'so it gets - cleaned up together with the batch (existing keep_instances_for_days
- cron). -
- Worker context now carries
zbs_current_batch_idso workers can - resolve their owning batch via the helper's
_current_batch()without - changing the worker API signature.
zbsync_ai_code 1.0 → 1.1
- New module: AI-powered code generation and automation for ZebrooSync. -
- AI providers
-
- Configurable AI provider records (OpenAI, Anthropic, Google Gemini) with
- API key storage and a default selection; unified single- and multi-turn
- call interface across all providers. -
- Auto-mapping wizard
-
- "Map" button on the mapper form analyses source/destination backend schemas
- and suggests field mappings (with action type and optional eval code).
- Supports bulk-selecting existing mappings for a targeted re-suggestion. -
- Code generation wizard
-
- "Generate Code" button on mapping and Python-transformer records.
- Accepts a natural-language instruction and returns ready-to-use Python code
- for eval expressions or full transformer worker bodies. -
- Pipeline creator wizard
-
- "Create Pipeline" buttons on the pipeline list and form header.
- Builds a complete multi-step ETL pipeline (workers, types, field values)
- from a plain-text task description. -
- Error analysis wizard
-
- "Analyse" button on batch execution records.
- Sends the error message, traceback and failed-record context to the AI and
- returns a plain-language root-cause explanation with fix suggestions. -
- AI chat assistant
-
- Floating chat panel (bottom-right, available across the whole Odoo UI)
- for ZebrooSync / Odoo / data-integration questions. -
- Dependency change
-
- Removed zbsync_mapper_import dependency; its functionality is now part of
- zbsync_mapper.
zbsync_excel_csv 1.2 → 1.3
_read_csvis now a generator: ityields one dict per row instead of- materialising the records into a list. The surrounding
withon _open_record_streamstays open for the lifetime of the generator- because Python keeps the function frame alive until the generator is
- exhausted, so the file handle is closed deterministically after the
- consumer (typically
dump_datawriting JSONL) is done. - - This unlocks end-to-end streaming with the new JSONL-output pipeline
- introduced in zbsync —
_process_worker_basenow propagates the - generator straight through to
dump_datawithout ever materialising - the records.
- CSV and Excel parsers now consume attachment-backed source records
- via
zbs.grabber_dumper._open_record_stream: the file is read directly - from the filestore line-by-line (
csv.reader(open(path))/ openpyxl.load_workbook(stream, read_only=True)) instead of loading- the full payload into RAM through
_extract_content. - - Inline
content-style records keep working — the new helper falls - back to BytesIO/StringIO transparently. -
- Pairs with the streaming source grabber changes in zbsync /
- zbsync_files / zbsync_ftp. End-to-end memory footprint for medium-
- sized CSVs (low-tens of MB) drops to the records-list materialisation
- cost only; the file content no longer doubles in RAM.
zbsync_files 1.3 → 1.4
zbs.grabber.filenow streams files above the size threshold into an- ir.attachment instead of loading them into RAM via read_text/read_bytes.
- Output records carry
_source_attachment_id(the attachment id) plus - filename, filepath and file_size; downstream parsers must read the
- attachment from the filestore (the parser-side streaming lands in a
- follow-up patch). -
- Small files (< zsync.streaming_threshold_bytes, default 10 MB) keep
- emitting inline
content— backward compatible.
zbsync_ftp 1.3 → 1.4
zbs.connection.ftpgets a newdownload_file_streamed(filename)- context manager that streams a remote file via retrbinary / SFTP.get
- into a local temp file and yields its path — no full RAM
- materialisation. The legacy
download_file()is kept as a thin wrapper - for backward compat. -
zbs.grabber.file.ftpuses this and, when the downloaded file exceeds- the streaming threshold, streams the temp file into an ir.attachment
- via
zbs.attachment.helperand emits_source_attachment_idin the - output record. Below the threshold the legacy inline
contentpath is - unchanged.
zbsync_mapper 1.2 → 2.0
- Mapper UX preview is rendered via textContent instead of innerHTML so
- external sample data can no longer be interpreted as HTML (XSS).
- Merged zbsync_mapper_import and zbsync_mapper_ux into zbsync_mapper.
- Full backend schema system, live preview, and mapping improvements. -
- Module merge
-
- zbsync_mapper_import and zbsync_mapper_ux are retired; all their
- functionality is now part of zbsync_mapper.
-
- Update any module that depended on zbsync_mapper_import or
- zbsync_mapper_ux to depend on zbsync_mapper instead. -
- Backend schema system
-
- New zbs.mapper.backend model: describes input/output data structures
- as Empty, Backend Model (JSON/YAML/XML), or Odoo Model (introspected).
-
- New zbs.mapper.backend.field: hierarchical field tree with lazy loading
- for Odoo models; auto-added to backend JSON on creation.
-
- New zbs.mapper.backend.category: hierarchical category tree for
- organising backends.
-
- Mappers gain input_backend_id / output_backend_id (external schemas) and
- input_odoo_model_id / output_odoo_model_id (Odoo sources/targets).
-
- integration_type field: ext_to_odoo, odoo_to_ext, ext_to_ext,
- odoo_to_odoo — replaces mapping_direction.
-
- field_source_id / field_dest_id M2O pickers on mappings for selecting
- backend fields with path breadcrumb display.
-
- action_generate_from_legacy() migrates raw dot-notation mappings to the
- structured backend system automatically. -
- Mapping improvements
-
- force_name is now a computed recursive field showing the full ancestor
- path of a mapping.
-
- New code field replaces format_value for eval expressions; migration
- 1.2 converts existing format_value values automatically.
-
- New action list_object combines list and object in one step.
-
- skip_record_expr: expression to abort processing the entire record.
-
- output_stream: routes a mapped value to a named env stream instead of
- the main record.
-
- has_duplicate_dest: computed warning when two mappings write the same
- destination field.
-
- action_sort_mappings() reorders mappings alphabetically by source/dest.
-
- List/object mappings now merge into existing values instead of
- overwriting. -
- Live UX preview (from zbsync_mapper_ux)
-
- ux_input_sample, ux_input_path, ux_input_mapped, ux_output_mapped,
- ux_preview fields for real-time mapping preview in the form.
-
- Drag-and-drop resequencing with automatic DFS resequencing of children.
-
- Embedded mapping list widget with search bar. -
- Breaking changes
-
- mapping_direction field removed — use integration_type instead.
-
- format_value field removed — migration converts to code automatically.
-
- Mappers using raw field names must run action_generate_from_legacy()
- to use the new backend field picker system.
-
- Modules depending on zbsync_mapper_import or zbsync_mapper_ux must
- update their dependencies to zbsync_mapper.
:::warning Breaking changes
- Merged zbsync_mapper_import and zbsync_mapper_ux into zbsync_mapper.
- Full backend schema system, live preview, and mapping improvements. -
- Module merge
-
- zbsync_mapper_import and zbsync_mapper_ux are retired; all their
- functionality is now part of zbsync_mapper.
-
- Update any module that depended on zbsync_mapper_import or
- zbsync_mapper_ux to depend on zbsync_mapper instead. -
- Backend schema system
-
- New zbs.mapper.backend model: describes input/output data structures
- as Empty, Backend Model (JSON/YAML/XML), or Odoo Model (introspected).
-
- New zbs.mapper.backend.field: hierarchical field tree with lazy loading
- for Odoo models; auto-added to backend JSON on creation.
-
- New zbs.mapper.backend.category: hierarchical category tree for
- organising backends.
-
- Mappers gain input_backend_id / output_backend_id (external schemas) and
- input_odoo_model_id / output_odoo_model_id (Odoo sources/targets).
-
- integration_type field: ext_to_odoo, odoo_to_ext, ext_to_ext,
- odoo_to_odoo — replaces mapping_direction.
-
- field_source_id / field_dest_id M2O pickers on mappings for selecting
- backend fields with path breadcrumb display.
-
- action_generate_from_legacy() migrates raw dot-notation mappings to the
- structured backend system automatically. -
- Mapping improvements
-
- force_name is now a computed recursive field showing the full ancestor
- path of a mapping.
-
- New code field replaces format_value for eval expressions; migration
- 1.2 converts existing format_value values automatically.
-
- New action list_object combines list and object in one step.
-
- skip_record_expr: expression to abort processing the entire record.
-
- output_stream: routes a mapped value to a named env stream instead of
- the main record.
-
- has_duplicate_dest: computed warning when two mappings write the same
- destination field.
-
- action_sort_mappings() reorders mappings alphabetically by source/dest.
-
- List/object mappings now merge into existing values instead of
- overwriting. -
- Live UX preview (from zbsync_mapper_ux)
-
- ux_input_sample, ux_input_path, ux_input_mapped, ux_output_mapped,
- ux_preview fields for real-time mapping preview in the form.
-
- Drag-and-drop resequencing with automatic DFS resequencing of children.
-
- Embedded mapping list widget with search bar. -
- Breaking changes
-
- mapping_direction field removed — use integration_type instead.
-
- format_value field removed — migration converts to code automatically.
-
- Mappers using raw field names must run action_generate_from_legacy()
- to use the new backend field picker system.
-
- Modules depending on zbsync_mapper_import or zbsync_mapper_ux must
- update their dependencies to zbsync_mapper. ------- END PATCH-NOTE ------ ---------PATCH NOTE--------- zbsync_marketplace 1.5 --> 1.6
- Odoo 19 compatibility: the marketplace item version uniqueness constraint
- moved from _sql_constraints (ignored on Odoo 19) to models.Constraint.
- Restore the worker "Upload to Marketplace" header button (server-action
- bindings on the abstract zbs.worker model never show up on the concrete
- workers); restrict the remaining marketplace server actions to form views
- so multi-select cannot hit ensure_one(); complete the @api.depends of the
- vault_url computes; drop the invalid password=True field parameter on the
- connection token field.
- Upload API refactor and button migration to server actions. -
-
- Upload calls now use marketplace_id.connection_id.upload({...}) directly
- instead of manually serialising to JSON and calling the legacy RPC path.
-
- Removed the unused json import from the upload wizard.
-
- Upload buttons migrated from inline form headers to ir.actions.server
- bindings, giving better permission and action-menu control.
:::
zbsync_marketplace_mapper 1.1 → 1.2
- Upload API refactor, consistent with zbsync_marketplace. -
-
- Upload calls now use marketplace_id.connection_id.upload({...}) directly
- instead of manually serialising to JSON and calling the legacy RPC path.
-
- Removed the unused json import from the mapper upload wizard.
zbsync_marketplace_transformer_helper 1.0 → 1.1
- Extensible button bar and UI layout improvements. -
-
- Extra buttons can now be injected via the zbs_helper_action_buttons
- registry category; each entry needs a label and a data-method attribute
- that maps to an Odoo method called on the current record.
-
- "Find in Code Collection" label shortened to "Find" to save space.
-
- Button bar switched to flexbox (d-flex); secondary buttons stay left,
- "Save To Code Collection" moves to the right (ms-auto).
zbsync_odoo 1.4 → 2.0
- Grabber / Dumper improvements and domain builder. -
- Domain builder
-
- New editable domain field widget (domain_editable) — build Odoo domains
- visually or as raw text with support for runtime Python expressions
- ($record.name, uid, etc.).
-
- limit and offset moved from the grabber to individual domain records,
- so different limits can be set per domain configuration.
-
- Domain form shows the interactive builder for local connections and
- readonly text for external connections. -
- Model selection
-
- New model_id Many2one (ir.model) on grabbers and dumpers — provides a
- dropdown picker for local connections instead of manual name entry.
-
- model_id is auto-populated by migration for existing local-connection
- workers that already have a model name set. -
- New grabber options
-
- browse_as_list toggle: returns each record individually to downstream
- workers instead of as a recordset (visible only in browse format mode).
-
- Default output format changed to browse; default connection defaults to
- the local Odoo instance. -
- New dumper options
-
- do_insert / do_update toggles control whether the dumper creates new
- records, updates existing ones, or both (both default to true).
-
- only_new_values field now includes help text explaining it skips
- unchanged fields to avoid unnecessary write bumps.
-
- connection_id now defaults to the local connection on new dumpers. -
- Connection defaults
-
- SSL enabled by default on new connections.
-
- Default port changed to 443 (HTTPS). -
- External API
-
- New external_fields_get() method on connections — lets clients fetch
- field metadata from remote Odoo instances (intended for the domain
- builder on external connections). -
- Migrations (2.0)
-
- Migrates limit/offset values from grabber records to their domain
- records. Workers with a non-zero limit but no domain record will log
- a warning to add one manually.
-
- Resets browse_as_list to False on existing grabbers so they keep the
- legacy recordset behaviour.
-
- Auto-populates model_id on existing local-connection workers. -
- BREAKING
-
- limit/offset fields were removed from zbs.grabber.odoo (moved to the
- domain records); external API users and old pipeline exports that
- reference them must switch to the domain-level fields.
-
- browse_as_list changes the grabber output shape when enabled; existing
- grabbers are kept on the legacy behaviour by the migration. Re-importing
- an old pipeline export creates the grabber with the new default
- (browse_as_list=True) — disable the toggle manually if the legacy
- recordset shape is required.
:::warning Breaking changes
- Grabber / Dumper improvements and domain builder. -
- Domain builder
-
- New editable domain field widget (domain_editable) — build Odoo domains
- visually or as raw text with support for runtime Python expressions
- ($record.name, uid, etc.).
-
- limit and offset moved from the grabber to individual domain records,
- so different limits can be set per domain configuration.
-
- Domain form shows the interactive builder for local connections and
- readonly text for external connections. -
- Model selection
-
- New model_id Many2one (ir.model) on grabbers and dumpers — provides a
- dropdown picker for local connections instead of manual name entry.
-
- model_id is auto-populated by migration for existing local-connection
- workers that already have a model name set. -
- New grabber options
-
- browse_as_list toggle: returns each record individually to downstream
- workers instead of as a recordset (visible only in browse format mode).
-
- Default output format changed to browse; default connection defaults to
- the local Odoo instance. -
- New dumper options
-
- do_insert / do_update toggles control whether the dumper creates new
- records, updates existing ones, or both (both default to true).
-
- only_new_values field now includes help text explaining it skips
- unchanged fields to avoid unnecessary write bumps.
-
- connection_id now defaults to the local connection on new dumpers. -
- Connection defaults
-
- SSL enabled by default on new connections.
-
- Default port changed to 443 (HTTPS). -
- External API
-
- New external_fields_get() method on connections — lets clients fetch
- field metadata from remote Odoo instances (intended for the domain
- builder on external connections). -
- Migrations (2.0)
-
- Migrates limit/offset values from grabber records to their domain
- records. Workers with a non-zero limit but no domain record will log
- a warning to add one manually.
-
- Resets browse_as_list to False on existing grabbers so they keep the
- legacy recordset behaviour.
-
- Auto-populates model_id on existing local-connection workers. -
- BREAKING
-
- limit/offset fields were removed from zbs.grabber.odoo (moved to the
- domain records); external API users and old pipeline exports that
- reference them must switch to the domain-level fields.
-
- browse_as_list changes the grabber output shape when enabled; existing
- grabbers are kept on the legacy behaviour by the migration. Re-importing
- an old pipeline export creates the grabber with the new default
- (browse_as_list=True) — disable the toggle manually if the legacy
- recordset shape is required. ------- END PATCH-NOTE ------ ---------PATCH NOTE--------- zbsync_odoo_flows 1.1 --> 1.2
- Odoo 19 compatibility: custom-data representation uses display_name
- instead of the removed name_get() (was crashing the pipeline-widget
- preview with AttributeError).
:::
zbsync_odoo_mapper 1.1 → 2.0
- External Odoo model sync and dropdown model selection. -
-
- New model_external_id Many2one field on OdooGrabber and OdooDumper
- for selecting models from the synced model list of an external
- connection instead of typing the model name manually.
-
- "Sync Models" button on the connection form fetches and stores the
- available models from the remote Odoo instance.
-
- zbs.backend.model extended with odoo_connection_id and odoo_model
- fields to track which models are available on each connection.
-
- Post-migrate script auto-populates model_external_id for existing
- grabbers/dumpers by syncing ir.model from their connections. -
- Breaking change
-
- Manual model name text entry is no longer available for external
- connections; models must be synced and selected from the dropdown.
:::warning Breaking changes
- External Odoo model sync and dropdown model selection. -
-
- New model_external_id Many2one field on OdooGrabber and OdooDumper
- for selecting models from the synced model list of an external
- connection instead of typing the model name manually.
-
- "Sync Models" button on the connection form fetches and stores the
- available models from the remote Odoo instance.
-
- zbs.backend.model extended with odoo_connection_id and odoo_model
- fields to track which models are available on each connection.
-
- Post-migrate script auto-populates model_external_id for existing
- grabbers/dumpers by syncing ir.model from their connections. -
- Breaking change
-
- Manual model name text entry is no longer available for external
- connections; models must be synced and selected from the dropdown. ------- END PATCH-NOTE ------ ---------PATCH NOTE--------- zbsync_pipeline_widget 2.1 --> 2.2
- Preview popover support and chart page layout. -
-
- onShowPreview callback added to the pipeline instance flow
- visualisation so batch rows can trigger a preview popover.
-
- Node height calculation updated to account for the preview button
- row when batches are present.
-
- Chart renderer moved from an inline group to a dedicated "Chart"
- notebook page, shown before other pages.
:::
zbsync_pipeline_widget_chart_preview 1.0 → 1.1
- New module: chart preview popover for pipeline batch rows. -
- Patches the pipeline renderer to add a preview popover that shows
- paginated input/output data from a batch execution. Uses
- zbs.instance.line.get_popover_texts / get_popover_field for data
- retrieval, with load-more support and per-field scrolling via the
- Odoo popover service.
zbsync_sql 1.2 → 1.3
- SQL-Dumper: mehrere Fehler behoben, durch die Daten nicht oder falsch
- geschrieben wurden. -
-
- MSSQL schrieb gar nicht: die Transaktion wurde nie committed
- (verschachtelte BEGIN/COMMIT TRANSACTION -> @@TRANCOUNT erreichte nie 0
- -> beim Schliessen der Verbindung wurde alles zurueckgerollt). Die
- Transaktionssteuerung liegt jetzt beim DB-Treiber (commit/rollback), es
- werden keine manuellen BEGIN/COMMIT/ROLLBACK-Statements mehr abgesetzt.
- Faellt ein Schreibvorgang mitten im Lauf fehl, wird sauber zurueckgerollt
- und die urspruengliche Fehlermeldung bleibt sichtbar. -
-
- Tabellen mit mehreren Schluesselspalten (zusammengesetzter Key): beim
- Suchen/Aktualisieren/Loeschen wurde nur die ERSTE Schluesselspalte
- beruecksichtigt -> es konnten falsche Zeilen aktualisiert/geloescht
- werden. Die WHERE-Bedingung wird jetzt korrekt ueber alle Schluessel
- gebildet. -
-
- Option "Recreate record": der bestehende Datensatz wurde geloescht, aber
- danach NICHT neu angelegt (Datenverlust). Jetzt wird nach dem Loeschen
- korrekt neu eingefuegt. -
-
- Der Plain-SQL-Worker (zbs.plain.sql) war in der Standard-Einstellung
- (nicht "pro Datensatz") nicht lauffaehig und lief mit ungerendertem SQL;
- ausserdem gab es doppelte Modelldefinitionen. Bereinigt und lauffaehig
- gemacht. -
- Zum Testen (Menue zSYNC -> Connections/Dumper):
-
- MSSQL-Dumper auf eine Zieltabelle laufen lassen und in der Ziel-DB pruefen,
- dass die Zeilen jetzt ankommen (Postgres verhaelt sich unveraendert).
-
- Eine Zieltabelle mit zusammengesetztem Schluessel (2+ Key-Spalten) updaten
- und pruefen, dass genau die richtige Zeile getroffen wird.
-
- "Recreate record" aktivieren, bestehenden Datensatz erneut dumpen und
- pruefen, dass er danach noch existiert (neu angelegt). -
- Hinweis: Das Feld "Use Transaction" schaltet nun Autocommit (aus = jede
- Anweisung committet sofort). Die Felder Begin/Commit/Rollback Transaction
- haben aktuell keine Wirkung mehr.
- New
streamingflag onzbs.grabber.sql: when set, rows are yielded - one at a time via the connection's new
iter_recordsgenerator and - the worker output flows straight into the JSONL output_data path (PR 3
- in zbsync). The whole result set never sits in RAM, regardless of how
- many millions of rows the query returns. -
- On Postgres
iter_recordsopens a server-side (named) cursor so the - database itself doesn't materialise the result either — true
- end-to-end streaming. Other engines fall back to client-side
fetchmany-loop streaming. -- Covered by the new
Big DB pipeline must stream through to success - test case in
test_bigdata_limits.robot: a local Postgres table is - populated via
generate_seriesand pulled through the pipeline under - the same 1 GB worker heap budget the file-based tests use.
zbsync_transformer_helper 1.1 → 1.2
- Code Helpers group is now shown only when the mapping action is eval.
- Simplified XML structure and visibility rules.
zbsync_trigger_methods 1.2 → 1.3
- Add deferred-reference queue tests (test_import_queue) to zbsync_trigger_methods
- where zbs.pipeline and zbs.trigger.methodhook are both available.
- Host the deferred-import-queue tests (moved from zbsync_xport, whose
- at_install run lacked zbs.pipeline / zbs.trigger.methodhook in the
- registry) and extend them: x2many resolver linking, zync_uuid=None
- guard, unresolvable use_existing list elements.
zbsync_uibinding 1.1 → 1.2
- instance_env added to button action eval context. -
- Button actions now receive instance_env (the parsed JSON of
- pipeline_instance.environment) alongside the existing
- pipeline_instance variable.
zbsync_web 1.3 → 1.4
- Content-type defaults, GraphQL removal, and view cleanup. -
-
- request_content_type now defaults to "application/json".
-
- response_content_type now defaults to "json".
-
- method now defaults to "get".
-
- GraphQL Query removed from request content type choices.
-
- Help text and examples in the web worker view condensed and
- reformatted with proper code tags.
- Odoo 19 compatibility: zbs.connection.web.auth replaced the removed
- name_get() override with _compute_display_name.
- New
streamingflag onzbs.web.worker. When set, the response body - is fetched with
requests.get(..., stream=True)and piped chunk-by- - chunk into an ir.attachment via the chunked filestore helper —
response.content/response.json()/ElementTree.fromstring- never touch the bytes. The output record carries
_source_attachment_id(and filename/file_size), the same shape the- streaming file-grabber emits, so a downstream CSV / XML parser
- consumes it through the existing attachment path. -
- Pagination, extract_path and response_content_type branches are
- bypassed in this mode — streaming is a single GET, the file lands in
- the filestore, and downstream workers take it from there. -
- Covered by the new
Big Web pipeline must stream through to success - test case in
test_bigdata_limits.robot: nginx is spun up in a - sibling container serving big.csv, the pipeline pulls it via HTTP
- and runs it through the same CSV parser the file-based test uses.
zbsync_web_oauth 1.0 → 1.1
- Fix cryptic "can only concatenate str (not 'bool') to str" error when an
- OAuth2 web auth is run without an application type selected. -
- When the "Application Type" (Mobile / Backend / Legacy) was left empty on an
- OAuth2 connection auth, the code did
getattr(self, "_" + self.application_type) - with
application_type == False, raising a TypeError during the sync run. - - Tester: open the connection -> Auth tab, set Auth Type = OAuth2 but leave
- "Application Type" empty. Saving now raises a clear validation error asking you
- to pick an application type, and running a batch no longer crashes with the
- TypeError - it tells you exactly what to configure. -
- Also fixes an AttributeError ("object has no attribute 'scopes'") when using
- Application Type = Mobile: the OAuth2 Mobile flow referenced a non-existent
scopesfield instead ofscope. The Scope field is now read correctly- (comma-separated), consistent with the Backend flow.
- Add an "Allow insecure transport (http)" option to OAuth2 connection auths. -
- oauthlib refuses OAuth2 over plain http and raises "InsecureTransportError:
- OAuth 2 MUST utilize https". This blocked syncs against local/dev endpoints
- that are only reachable via http. -
- Tester: open the connection -> Auth tab (Auth Type = OAuth2). There is a new
- checkbox "Allow insecure transport (http)". Leave it off for production
- (https). Only tick it when the token/authorization URL is a local/dev http
- endpoint - the sync then no longer aborts with the InsecureTransportError.
zbsync_xml 1.1 → 1.2
- New
stream2recordsttype onzbs.transformer.xml: parses XML via lxml.etree.iterparseand yields one dict per<root_element_name>- element. Generator-based, so it pairs with the JSONL-output streaming
- in zbsync (PR 3) — record subtree is
.clear()-ed after each yield, - and preceding siblings are dropped so the in-memory document never
- grows beyond a single record. -
- When the input record carries
_source_attachment_id(streaming - file-grabber), the XML file is opened directly from the filestore;
- otherwise the helper wraps inline content in BytesIO. Same dual-path
- shape as the CSV parser. -
- This lets a flat
<root><record>...</record></root>document of - effectively any size stream through the pipeline under a tight
- worker heap budget — covered by the new test case `Big XML pipeline
- must stream through to success` in test_bigdata_limits.
zbsync_xport 1.4 → 1.5
- Fix zync_uuid being overwritten on every create(): the guard checked
vals_list(always truthy) instead ofval, causing imported records- to get a fresh UUID and then be deleted by _import_reconcile_o2m.
- Odoo 19 compatibility fixes.
-
- export/import by_name now uses display_name instead of the removed
- name_get() (was crashing with AttributeError on Odoo 19).
-
- zync_uuid uniqueness migrated from _sql_constraints to models.Constraint
- so the DB constraint is actually created on Odoo 19.
- Import robustness fixes from the 5-way review of the marketplace branch:
- deferred use_existing elements inside x2many lists are queued per element
- and linked by the resolver instead of silently dropping the whole field;
- the resolver refuses to match records via an empty zync_uuid; the
- self-reference skip only applies to the actual o2m inverse field;
- _import_reconcile_o2m keeps records created by the import itself and
- records referenced via use_existing, and an empty o2m list now removes
- all previous sub-records; password/token-like field values are excluded
- from the import change-log.
zbsync_xport_ui 1.7 → 1.8
- Fix AttributeError in import wizard when change_log was non-empty:
- ok() called _format_change_log() but the method is named _format_change_log_html().
- Pre-import Odoo model reference validation. -
- Before completing a pipeline import, the importer now scans all worker
- configs for unresolved Odoo model references (xmlid or by_name lookups)
- and blocks the import with a clear error message listing the missing
- models. Implemented via _collect_missing_odoo_model_refs() and
- _walk_odoo_model_refs().
- Import wizard fixes: ok() no longer crashes with AttributeError when a
- change-log exists (undefined _format_change_log); error/warning detection
- is based on the raw log messages instead of the rendered HTML (field
- diffs containing "ERROR" no longer abort the import); the sequence value
- from the import JSON is HTML-escaped (XSS); the log field is readonly and
- the result HTML is wrapped in a scrollable container.
- Regressionstest für ZO-05230: ein Import ohne "Start"/"Stop"-Schritte (wie er
- beim Marketplace-Download entsteht) muss "Start" wieder an erste und "Stop" an
- letzte Position setzen.
2026-06-08
zbsync_xport_ui 1.6 → 1.7
- Import wizard log field upgraded to fields.Html with rich diff view:
- collapsible unified diffs (dark theme) for code/text changes,
- inline old→new for short values, color-coded action badges.
- log field changed from Text to Html (sanitize=False).
zbsync_xport 1.3 → 1.4
- load() tracks import changes via _xport_change_log context list:
- created/updated/deleted workers and scalar field diffs.
- Helpers: _xport_log_change, _xport_record_label, _xport_scalar_changes.
zbsync_xport_ui 1.5 → 1.6
- Import wizard now shows a structured change-log after import:
- which pipeline steps were created/updated/deleted and which
- fields changed (old → new value). Changes are also posted as
- a chatter message on the pipeline.
zbsync_xport 1.2 → 1.3
- load() now deletes one2many sub-records (e.g. pipeline steps) whose
- zync_uuid is absent from the import JSON, so removing a step from an
- export file removes it from the existing pipeline on re-import.
zbsync_xport_ui 1.4 → 1.5
- Added import/export scenario tests for pipelines with Python worker and
- mapper: reset changes, apply JSON changes, delete step, add new step.
zbsync 1.12 → 1.13
- zbs.trigger.pipeline_id gets xport_ignore=True so pipeline exports no
- longer produce a circular use_existing self-reference for trigger.pipeline_id.
zbsync_trigger_methods 1.1 → 1.2
- Added regression tests for ZO-04788: pipeline import with method_trigger_ids
- containing a use_existing self-reference for pipeline_id.
zbsync_xport 1.1 → 1.2
- Fixed KeyError when importing pipelines whose method_trigger_ids contain a
- use_existing self-reference (trigger.pipeline_id → the pipeline being imported).
- Introduced DeferredReference exception and _import_resolve_deferred() queue
- that retries unresolved references after the record is created.
2026-06-04
zbsync 1.11 → 1.12
- Pipeline grouping by tags is now sorted alphabetically again, version-safe
- across Odoo 17 (read_group) and 18+/19 (formatted_read_group), honouring an
- explicit descending order. Fixed pipeline line
- form fields that were accidentally shown (column_invisible -> invisible),
- removed a duplicate Zebroo-Sync privilege record, and hardened the
- recordset merge against a dict/list mismatch crash.
zbsync_marketplace 1.4 → 1.5
- Fixed the Python-worker marketplace upload that crashed after the
- connection API migration (now uses connection.upload). The catalog finder
- renders descriptions from the sanitized field only (XSS fix), the migration
- folder version was corrected so it actually runs on upgrade, and catalog
- refresh now whitelists the fields it creates.
zbsync_marketplace_mapper 1.0 → 1.1
- Fixed the mapper marketplace upload/download round-trip: it now uses the
- current connection API, the python_code item type, and a content shape that
- matches the download side, so uploaded mappers can be found and downloaded
- again.
zbsync_odoo_flows 1.0 → 1.1
- Odoo 19 compatibility: declare the _inherits reference field (item_id) on
- of.zync.pipeline with delegate=True so the registry loads.
zbsync_transformer_helper 1.0 → 1.1
- The helper export route (/zync/transformer_helper/download) is now restricted
- to Zebroo-Sync managers and validates the requested ids instead of raising a
- server error on bad input, matching the pipeline export routes.
zbsync_xport_ui 1.3 → 1.4
- Pipeline export routes (/zync/download and /zync/download_pipeline_xml) are
- now restricted to Zebroo-Sync managers and validate the requested id
- instead of raising a server error on bad input.
2026-05-26
zbsync_xml 1.0 → 1.1
- Add optional XSLT field on the XML worker. When set, the input XML is
- transformed via the stylesheet before being parsed (xml2dict / lxml2dict).
2026-05-21
zbsync 1.10 → 1.11
-
- Configuration: new "Python-Steps" menu listing all zbs.transformer.python
- records (analog to Connections/Grabbers/Dumpers).
-
- zbs.cronstart: optional
zbs_environment_idfield. When set, the cronjob
- zbs.cronstart: optional
- starts the pipelines with that environment (explicit
zbs_environment - kwarg still wins). Shown in the form view; hidden-by-default column on
- the list.
2026-05-19
zbsync_pipeline_widget 2.0 → 2.1
- test_add_worker_edge: rename worker arg from "Demo-Data" to "Demo Data"
- (f1a42141e renamed the zbs.const description). Test-only.
zbsync_odoo 1.3 → 1.4
- Robot tests + dumper.robot.template: switch from "Odoo Button text=..."
- (OWL chart) to the new "Zync Open Worker From Chart" helper which finds
- workers on the Svelte chart by title and clicks the hover-revealed edit
- button. ZO-04608 Chart UX. Test-only.
zbsync_ftp 1.2 → 1.3
- Robot tests: adapt worker keyword + worker name strings to the
- ZO-04608 Chart UX rewrite (Svelte chart, worker renames). Test-only.
zbsync_odoo 1.2 → 1.3
- Robot tests: adapt worker keyword + worker name strings to the
- ZO-04608 Chart UX rewrite (Svelte chart, worker renames). Test-only.
zbsync_odoo_mapper 1.0 → 1.1
- Robot tests: adapt worker keyword + worker name strings to the
- ZO-04608 Chart UX rewrite (Svelte chart, worker renames). Test-only.
zbsync_xport_ui 1.2 → 1.3
- Replace web_diffview HTML diff with a native Owl pipeline_diff widget.
- Per-step collapsible field-level diff with smart matching (zync_uuid +
- sequence/worker fallback), nested-dict recursion, and noise-key skipping.
- Wizard closes on warn-only imports and posts warnings to the pipeline
- chatter; errors still keep it open.
zbsync 1.9 → 1.10
- Bugfixes in zebrooset (Recordset-Wrapper):
-
- B1: _Dive int-index on raw dict crashed in Python 3 (dict_keys not subscriptable).
-
- B2: _loads now actually uses the _prepare_load hook result (was discarded).
-
- B3: Decoder no longer crashes on unknown _type markers; mirrors Encoder try/except.
-
- B4: _recursive_dict_merge handles multi-element lists instead of crashing.
-
- B5/B7/B8: dead code removed in _WrappedDict._iterate_records, Decoder, and check_setattr_forbidden.
-
- B6: _merge return value handled consistently across ZebrooSet/_WrappedDict/_WrappedList.
- Plus regression tests for B1-B4.
zbsync 1.8 → 1.9
- Demo data: rename
groups_idtogroup_idson the res.users record for - the admin assignment to zbsync.group_manager. Odoo 19 renamed the
- Many2many field; without this, admin no longer gets the manager group
- in demo mode, which broke robotests requiring manager-level access.
zbsync_pipeline_widget 1.0 → 2.0
- Replaces the old pipeline/instance charts completely with custom Svelte charts.
-
- Creates a clear visiual differenciation between pipeline and instance chart
-
- Allows adding workers directly in place: with a + button between existing nodes
-
- Adds drag-drop reordering of workers
-
- Adds deleting & disabling of workers
-
- Adds a preview of the worker comment/documentation
-
- Adds clear edit & line detail buttons: instead of clicking different chart sections
2026-05-13
zbsync 1.7 → 1.8
- Pipeline overview:
-
- Several Workers renamed
-
- Description added to pipelines
-
- Tabs restructured, icons added
-
- Workers renamed to Steps. Columns tidied up. Line details accessible via icon at the start of the row now. Technical name not visible by default, only by selection.
-
- Triggers grouped and renames as Automation
-
- Description added to Versioning, and auto-population with version number
-
- Details renamed to Advanced.
-
- Module XML removed and replaced by a download button in the Versioning tab
- Pipeline list view:
-
- sorting added for pipelines and tags
-
- additional columns included
-
- existing columns made optional
- Menus
-
- Mapper menu integrated into Configuration
-
- Worker Components section added to Configuration (to be further populated later)
2026-05-12
zbsync_marketplace 1.2 → 1.3
- Fix wiz_upload_python view referencing fields (uniqueid, changelog) that
- were never added to the zbs.marketplace.upload.python model. Restored
- previous working view so module installs again.
2026-05-04
zbsync 1.6 → 1.7
- Fix stuck instances: cron_heartbeat now recovers instances where all batches are done but state is still running
zbsync 1.5 → 1.6
- Fix stuck instances: cron_heartbeat now recovers instances where all batches are done but state is still running
2026-04-30
zbsync_marketplace 1.1 → 1.2
- Remove live-fetch from onchange handlers; use local version cache and local content in make_pipeline
2026-04-29
zbsync_xport_ui 1.0 → 1.1
- Fix trailing comma in _remove_uuids causing json.loads failure on Python 3.13
zbsync_odoo 1.1 → 1.2
- Fix "Cursor already closed" error in _get_obj: removed ormcache so each batch
- gets a fresh env[model] bound to its own cursor instead of a stale closed one.
2026-04-27
zbsync_receiver 1.0 → 1.1
- Receiver: log pipeline run exception via _logger.exception for diagnostics
zbsync 1.4 → 1.5
- Populate zbs.encoding with all Python-supported character encodings (101 total)
- Add all Python-supported encodings to encoding list
- Add uuid to default objects available in expressions
- Fix continue_immediately: enqueue batches via HTTP immediately instead of
- waiting for cron pusher, and read continue_immediately flag before advancing
- to next pipeline line.
zbsync_excel_csv 1.1 → 1.2
- Add test for CSV import with latin1 encoding
- Add unit test for importing ISO-8859-1 encoded CSV files
zbsync_files 1.2 → 1.3
- File dumper now uses _eval_expression for filepath, making datetime, uuid etc. available
zbsync_ftp 1.1 → 1.2
- FTP dumper uses _eval_expression for filepath, fix pwd() bug in FTP connection, auto-mkdir before upload, add robot test
- Fix FTP connection pwd call and use eval_expression for filepath in dumper
zbsync_marketplace 1.0 → 1.1
- Fix missing api import in choose_worker.py
zbsync_sql 1.1 → 1.2
- Fix pytds compatibility: use dsn instead of host, move as_dict to connect()
zbsync_uibinding 1.0 → 1.1
- Fix zync UI button in tree/list view to handle multiple selected records.
- Add batch_mode option: when enabled, a single pipeline is started with all
- selected records instead of one pipeline per record.
zbsync_webdav 1.1 → 1.2
- Use eval_expression for local_path in WebDAV grabber
2026-03-31
zbsync_files 1.1 → 1.2
- Fix destination_path overwrite in after_commit causing cascading _001_002_003 suffixes
zbsync_ftp 1.0 → 1.1
- Fix off-by-one error in grabber file limit — processed one file too few
zbsync_webdav 1.0 → 1.1
- Fix off-by-one error in grabber file limit — processed one file too few
2025-05
- switching from outdated pymssql to python-tds - compatibility with debian packages
2025-04
-
BREAKING: renamed following functions to just "_as_python_object()" in zebrooset from
- as_json
- _as_python_type
- _as_plain_python
- _get_python_type
Affected: perhaps local created python transformers / code snippets
2025-03
- BREAKING: file grabber: just one expression for folders; recursive expression is extra
2024-07
- BREAKING: button after success turned from json to python
- BREAKING: fileupload dialog and buttons - delete existing data
2024-06
- change the code in cronjobs to start with .start() --> .start(data=None, manual=False)
- BREAKING: xml2dict - result in content
2024-01
- deleting all mappings: making a json snapshot before
- BREAKING: mapping: browse objects (local ones or rpc remote objects) of odoo now export many2one fields in direct mappings as int/False instead of lists
2023-10-12
- BREAKING: Triggers - Web Worker looses data, Triggers are lost!