Squeeze for Dynamics 365 BC - de-DE
Handbuch zur Administration und Nutzung von SQUEEZE for Microsoft Dynamics 365 Business Central.
SQUEEZE ist eine Mandanten-fähige Software-Lösung für Dokumenten-Klassifikation und Inhaltsextraktion.
Es ist ein vollständig webbasiertes System zur Verarbeitung von elektronischen Dokumenten, mit wesentlichem Fokus auf die Erkennung und Auslesung von Eingangsdokumenten im B2B Sektor.
- Systemvoraussetzungen
- Installation
- Konfiguration & Administration
- Berechtigungssätze
- DEXPRO Core
- SQUEEZE Einrichtung
- Dokumentenklassen Einrichtung
- Kreditorenbezogene Einrichtung
- Kontierungseinrichtungen
- Feldzuordnung
- Benutzerdefinierte Feldzuordnung
- Benutzerspezifische Einrichtung
- Squeeze Stammdatentabellen
- SQUEEZE
- Rollencenter-Aktivitäten
- Validierung
- SQUEEZE Beleg Übersicht
- Mandantenübergreifende Belegansicht
- Importwarteschlange
- SQUEEZE Belegvalidierung
- Lieferantenspezifisches Training
- Dokument Aufteilen
- Bestell- & Wareneingangsabgleich
- Bestell-/ Wareneingangszeilen manuell importieren
- Externer Viewer
- Belege hochladen
- SQUEEZE Warteschlange
- Viewer im Ziel-Beleg
- Plausibilitätsprüfungen
- Auftragsbestätigungen
- Extension Entwicklung
- Squeeze-Ursprungsanhang anpassen
- Abweichende Verwendung der SQUEEZE Anhänge
- Anpassung der Dateinamen von Anhängen nach der Validierung
- Hinzufügen eines Feldes in der Validierung (ab Version 2.10)
- Implementierung eines benutzerdefinierten, automatischen Bestellabgleichs
- Implementierung einer neuen, generischen Dokumentenklasse
- Erstellung benutzerdefinierter Dokumente (Individuelle Verarbeitung)
- Einbetten des SQUEEZE Viewer‑Parts in eigene Pages
- Hinzufügen eines Feldes in der Validierung (bis Squeeze BC APP Version 1.*)
- Hinzufügen eines Feldes in der Validierung (ab Version 2.0)
- Regelbasierter nächster Prozessschritt: Belege in „Individuelle Verarbeitung“ steuern
- Events nach der Erstellung eines SQUEEZE-Belegs (CreateSource)
- Events nach der Erstellung eines Core-Belegs (DXP Document)
- FAQ
Systemvoraussetzungen
Systemvoraussetzungen zur Nutzung von SQUEEZE for Dynamics 365 BC
Unterstützte Microsoft Dynamics 365 Business Central Versionen
Die Microsoft Dynamics 365 Business Central Integration ist auf Grund von technischen Mindestvoraussetzungen ab folgender Version möglich:
Unterstützte Microsoft Dynamics 365 Business Central Versionen
Voraussetzung zum Betrieb ist, dass die jeweilige Microsoft Dynamics 365 Business Central Version sich noch im regulären Support befindet. Der erweiterte Support (extended Support) wird ausgeschlossen.
Unterstützte SQUEEZE Versionen
Die Integration von SQUEEZE in Microsoft Dynamics 365 Business Central benötigt für den Betrieb ein lizensiertes SQUEEZE System ab der Version 2.20.0.
Bei der Kombination aus einem Cloud BC und einem OnPrem Squeeze, muss beachtet werden, dass BC die Belege aus dem PULL Export von Squeeze abholt. Somit muss das Squeeze System aus der BC Cloud Umgebung erreichbar sein.
Microsoft hat hierzu diesen Artikel erfasst: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/security/security-service-tags#destination-service-supports-network-access-rules-with-ip-ranges
Installation
Lizenzen
Microsoft
Informationen zu den Microsoft Business Central Lizenzen.
SQUEEZE
Das DEXPRO SQUEEZE System welches an Business Central angeschlossen werden soll benötigt eine gültige Kunden-Lizenz.
Bezug der DEXPRO Module
Detailliertere Informationen finden Sie hier.
OnPrem
Für OnPrem Installationen wird auf Anfrage eines registrierten Resellers / Partners ein Runtime Package mit den benötigten Apps zur Verfügung gestellt. Diese werden durch den Partner der Kundenlizenz hinzugefügt und im Anschluss in das Microsoft Dynamics Business Central eingespielt.
Cloud
Für Cloud Installationen benötigt man lediglich Zugriff auf den Microsoft AppSource. Hier werden die benötigten DEXPRO Apps heruntergeladen.
Einrichtungsassistent
Wenn die SQUEEZE Einrichtung das erste mal geöffnet wird, wird man von dem SQUEEZE Einrichtungsassistenten begrüßt.
Dieser führt den Anwender Schritt für Schritt durch die unterschiedlichen Einrichtungen des Moduls.
Start
Auswahl SQUEEZE System
In diesem Schritt wird die URL von dem SQUEEZE System hinterlegt.
Beispiel: https://demo.msbc.squeeze.one
Anmeldung am SQUEEZE System
In diesem Schritt melden Sie sich mit einem gültigen SQUEEZE User mit der Admin Rolle an dem Squeeze System an. Sie können dies entweder direkt über den API-Schlüssel tun oder alternativ über einen Adminuser per Benutzernamen und Kennwort. Die Daten der Zweiten Option werden nur für die Einrichtung einmalig verwendet. Im Anschluss wird von dem User der API-Schlüssel im Hintergrund gezogen. Zukünftig erfolgt die Anmeldung am SQUEEZE System im Hintergrund immer per API-Schlüssel.
Über die Schaltfläche "API-Schlüssel" können Sie zwischen den Anmeldeoptionen wechseln.
Unverarbeitete Einträge der Importwarteschlange
Sollte die abgebildete Meldung erscheinen, so liegen noch unverarbeitete Einträge in der Importwarteschlange vor. Dies kann vorkommen, wenn andere Mandanten bereits mit einem Squeeze verbunden sind. Dies stellt kein Problem dar, da sich diese Belege noch nicht in der Validierung befinden. Diese werden beim nächsten Importlauf automatisch wieder von Squeeze runtergeladen.
Zuweisung der Dokumentenklasse
In diesem Schritt wähle Sie die Squeeze Dokumentenklasse aus, welche angebunden werden soll.
Nummernserie für die SQUEEZE Belege
In diesem Schritt wähle Sie eine Nummernserie für die Core Belege und eine für die SQUEEZE Belege aus. Sollte noch keine existieren, so können Sie über die Nummernserienauswahl auch einen neuen Eintrag anlegen.
Abschluss
Durch den Klick auf "Fertigstellen" beenden Sie den Einrichtungsassistenten. Im Anschluss wird die SQUEEZE Einrichtung geöffnet. Weitere Konfigurationsmöglichkeiten werden hier beschrieben.
Konfiguration & Administration
Berechtigungssätze
Um die Module nutzen zu können, muss den jeweiligen Anwendern der passende Berechtigungssatz zugewiesen werden.
Folgende werden mit ausgeliefert:
- DXP Core Admin - DEXPRO Core Administrator
- DXP Core User - DEXPRO Core Benutzer
- DXP SQUEEZE Admin - DEXPRO SQUEEZE Administrator
- DXP SQUEEZE User - DEXPRO SQUEEZE Benutzer
DEXPRO Core
Der DEXPRO Core verwaltet die einzelnen DEXPRO Apps und deren Dokumente pro Mandant.
Es werden alle Belege, welche über die unterschiedlichen DEXPRO Module in Microsoft Dynamics 365 Business Central eingelaufen und verarbeitet worden sind, angezeigt. Zur Nachvervolgung von einzelnen Belegen wird auf eine globale Nummernserie, welche über alle DEXPRO Apps genutzt wird, gesetzt. Dies bietet den Vorteil, dass die Anwender mit nur einer Nummernserie pro Beleg arbeiten.
Weitere Informationen finden sie hier.
SQUEEZE Einrichtung
In der SQUEEZE Einrichtung wird sowohl die Anbindung an das SQUEEZE System, als auch die Verarbeitung innerhalb der App eingerichtet.
Menü
Start
Einrichtungsassistent
Hier rüber wird der Einrichtungsassistenz gestartet. Dieser führt den Anwender Schritt für Schritt durch alle Menüpunkte.
Einrichtung kopieren
Hiermit wird die Einrichtung in andere Mandanten kopiert.
API-Schlüssel holen
Über diese Funktion wird mithilfe von Benutzername und Passwort der erste API-Schlüssel des angeschlossenen SQUEEZE System geholt und im isolierten Speicher abgelegt.
Hintergrundjobs anlegen
Die automatisierte Abholung und Verarbeitung von Dokumenten aus SQUEEZE erfordert die Einrichtung eines Hintergrundjobs. Dies kann in über diese Funktion durchgeführt werden.
Stammdaten
Squeeze Stammdatentabellen
Öffnet eine Übersicht über die Stammdatentabellen, die bei einer Synchronisierung mit Squeeze berücksichtigt werden.
Navigation
SQUEEZE-Verknüpfungen (obsolet)
Über den Menüpunkt SQUEEZE-Verknüpfungen kann man einsehen welcher Kreditor bzw. welches Kreditorenbankkonto welche ID auf der Squeeze Seite hat.
Benutzerspezifische Einrichtung
Über diesen Menüpunkt erreichen Sie die benutzerspezifische Einrichtung. In dieser können abweichende Regeln je Anwender hinterlegt werden.
Importwarteschlangen-Einrichtung
In diesem Menü wird eine Liste von SQUEEZE Belegen angezeigt, die bereit für den Import in die SQUEEZE for BC App sind. Durch das Ändern des Systemfilters ist es ebenfalls möglich, bereits importierte Belege einzusehen.
Kreditorenbezogene Einrichtung
Über diesen Menüpunkt erreichen Sie die kreditorenbezogene Einrichtung. In dieser können abweichende Regeln pro Kreditor hinterlegt werden.
Dokumentenklassen Einrichtung
Über diesen Menüpunkt erreichen Sie die Einrichtung für die SQUEEZE Dokumentenklassen.
FastTabs
Allgemein
In diesem FastTab kann man die Nutzung dieser App aktivieren/Deaktivieren. Zusätzlich sieht man die Version des angeschlossenem SQUEEZE-Systems.
API
In diesem Fasttab wird die URL des SQUEEZE Systems angegeben. Des Weiteren wird ein API-Name gesetzt und der dazugehörige API-Schlüssel über die Funktion "API-Schlüssel holen" eingetragen. Bei jedem Öffnen der SQUEEZE Einrichtung wird zudem die Verbindung zum verbundenen SQUEEZE Mandanten überprüft.
Nummernserie
Hier wird die Nummernserie für die SQUEEZE Belege angegeben.
Hintergrundjobs
Für die automatisierte Abholung von Belegen aus SQUEEZE sowie deren Verarbeitung und Bereinigung ist die Einrichtung von Hintergrundjobs notwendig. Folgende Codeunits werden automatisch angelegt, sobald die entsprechende Aktion (Hintergrundjobs anlegen) in der SQUEEZE Einrichtung ausgeführt wird:
In der SQUEEZE Einrichtung sind die Aufgabewarteschlangenposten anschließend verknüpft.
Sicherheit
In diesem FastTab befinden sich sicherheitsrelevante Einstellungen:
- Dokument-Token verwenden: Wenn aktiviert, wird anstelle des API-Schlüssels ein dokumentspezifisches Zugriffstoken für Viewer-URLs verwendet. Das Token ist 30 Minuten gültig und wird automatisch erneuert. Dies erhöht die Sicherheit, da der API-Schlüssel nicht in Browser-URLs übertragen wird.
Viewer
In diesem FastTab befinden sich Einstellungen zum SQUEEZE Viewer:
- Viewer im Ziel-Beleg: Wenn aktiviert, wird der SQUEEZE Viewer als Infobox (FactBox) auch in den resultierenden Zielbelegen angezeigt, z. B. in Einkaufsrechnungen und Einkaufsbestellungen. So können Anwender den ursprünglich gescannten Beleg auch nach der Validierung jederzeit einsehen, ohne zum SQUEEZE-Beleg zurückkehren zu müssen.
Job-Einstellungen
Zusätzlich zu den Hintergrundjobs selbst kann in den Job-Einstellungen der folgende Wert konfiguriert werden:
- Bereinigungsintervall (Datumsformel): Definiert, wie alt die zur Löschung markierten Belege sein müssen, bevor sie bereinigt werden. Beispiel:
-1Mbedeutet, dass Belege mindestens einen Monat alt sein müssen.
Dokumentenklassen Einrichtung
In der SQUEEZE Dokumentenklassen Einrichtung wird die Zuordnung zwischen der jeweiligen Dokumentenklasse und Ihrer Exportschnittstelle vorgenommen. Des Weitern wird hier die Feldzuordnung jeder Dokumentenklasse heruntergeladen und so ein Set an Standard Feldern und deren Verwendung in Microsoft Dynamics 365 Business Central hergestellt.
Die Dokumentenklassen Einrichtung ist App übergreifend und wird über den DEXPRO Core verwaltet.
Start
Feldzuordnung herunterladen
Hiermit wird die Feldstruktur der SQUEEZE Dokumentenklasse heruntergeladen. Diese werden für die Metadaten-Zuordnung benötigt.
Navigation
Feldzuordnung
Über diesen Menüpunkt erreichen Sie die Feldzuordnung. In dieser wird definiert welche Felder aus dem Squeeze-Endpunkt an die definierten Felder in Microsoft Dynamics 365 Business Central übertragen werden. Die Standardfeldzuordnung ist nicht editierbar. Abweichende Zuordnungen können über die Benutzerdefinierte Feldzuordnung realisiert werden.
Kreditorenbezogene Einrichtung
Über diesen Menüpunkt erreichen Sie die kreditorenbezogene Einrichtung. In dieser können Sie je Kreditor abweichende Einstellungen zu den Standardeinrichtungen der Dokumentenklasse vornehmen.
Liste
Dokumentenklassen
In dieser Übersicht werden alle eingerichteten Dokumentenklassen aufgelistet.
Karte
Dokumentenklasse
Hier wird jede Dokumentenklasse individuell eingerichtet.
Allgemein
In diesem FastTab wird der Name der Dokumentenklasse, der nächste Prozessschritt, sowie die automatische Anreicherung der Positionen eingerichtet.
Squeeze
Standardbuchungsdatum
Analog zum BC Standard haben Sie die Möglichkeit, ein Buchungsdatum als Standard zu definieren, sofern anderweitig noch keins eingetragen wurde (z.B. durch die Benutzerdefinierte Feldzuordnung). Sie können zwischen dem Arbeitsdatum, der Standard BC Einrichtung "Kreditoren & Einkauf Einr." und dem heutigen Datum wählen.
Autovervollständigen:
Bei Belegen ohne Bestellbezug kann das System sich die eingelesenen Positionen und die darauf angewandte Kontierung pro Kreditor merken und wieder abrufen. Hierfür gibt es drei Optionen, die gewählt werden können.
- Niemals: Deaktiviert die Funktion und blendet den Button in der Validierungsseite aus
- Manuell: Das Anwenden der Daten für die Autovervollständigung erfolgt manuell per Klick auf den Button "Autovervollständigen". Die Speicherung der Metadaten für die Autovervollständigung wird automatisch beim Abschluss des Validierungsprozesses ausgeführt
- Automatisch: Das Erstellen und Anwenden der Daten für die Autovervollständigung erfolgt automatisch
- Beim Erstellen des SQUEEZE Beleg werden die Einträge angewendet
- Beim Abschluss der Validierung werden die Einträge erstellt/aktualisiert
Automatische Validierung:
Aktivieren Sie diese Option, damit Squeeze for BC eingehende Belege automatisch validiert. Bitte beachten Sie, dass diese Funktion nur im Falle vollkommen plausibler Daten funktioniert.
Anhänge herunterladen:
Aktivieren Sie diesen Schalter, um beim Erstellen eines neuen Belegs automatisch SQUEEZE Anhänge herunterzuladen.
Anhänge in den Zielbereich transferieren:
Hierrüber richten Sie ein, ob die SQUEEZE Anhänge in den Zielbeleg transferiert werden sollen.
Kontierungscode:
Gibt die Kontierungseinrichtung an, die bei der Durchführung der Kontierung im Validierungsprozess verwendet werden soll.
API Einstellungen
An dieser Stelle wird die der Dokumentenklasse entsprechende ID des verbundenen Squeeze Mandanten hinterlegt sowie die ID der Pull-Export-Schnittstelle, als auch die korrekte Line Table ID. Die Standardwerte stimmen nicht zwangsläufig mit der Einrichtung im Squeeze Mandanten überein und sollten gegengeprüft werden.
Bestellabgleich
Der Bestellabgleich dient zur automatisierten Überprüfung der ausgelesenen Positionen mit denen der noch offenen Bestellungen in Microsoft Dynamics 365 Business Central. In diesem FastTab werden die zulässigen Betrags- & Mengentoleranzen für den Abgleich eingerichtet. Zusätzlich kann festgelegt werden, ob der Abgleich gegen Bestellungen oder Lieferungen statt finden soll. Wenn "Daten ersetzen" aktiv ist, werden die Beträge und Beschreibungen der Positionen mit denen der Bestellung/Lieferung nach dem Abgleich ersetzt.
Plausibilitätsprüfung
An dieser Stelle können Sie einzelne Plausibilitätsprüfungen deaktivieren.
Bestellnummer im Kopf anzeigen
Über den Schalter Bestellnummer im Kopf anzeigen kann eingestellt werden, ob die erkannte Bestellnummer im Kopfbereich des SQUEEZE-Belegs als Feld dargestellt werden soll.
Dokumententeilung deaktivieren
Über den Schalter Dokumententeilung deaktivieren kann die Funktion "Dokument aufteilen" für diese Dokumentenklasse deaktiviert werden. Wenn aktiviert, steht die Belegtrennung in der Validierungsseite nicht zur Verfügung.
Bestellungszuweisung zulassen
Über den Schalter Bestellungszuweisung zulassen kann festgelegt werden, ob SQUEEZE-Positionen manuell Bestellzeilen zugewiesen werden dürfen.
Gesperrten Lieferanten (Zahlung) ignorieren
Über den Schalter Gesperrten Lieferanten (Zahlung) ignorieren kann eingestellt werden, ob Kreditoren mit dem Gesperrtstatus "Zahlung" bei der Plausibilitätsprüfung nicht als fehlerhaft markiert werden sollen.
Regeln
An dieser Stelle können Sie anhand der Rules Engine regelbasierte Einrichtungen vornehmen. Die Rules Engine ermöglicht es, anhand von Bedingungen automatisiert Entscheidungen zu treffen:
- Regelgruppe f. nächsten Prozessschritt: Definiert die Regelgruppe, die den nächsten Prozessschritt bestimmt. So kann z. B. festgelegt werden, dass Belege bestimmter Kreditoren oder ab einem bestimmten Betrag in eine individuelle Verarbeitung geleitet werden.
- Regelgruppe f. Kontierungscode: Definiert die Regelgruppe, die den zu verwendenden Kontierungscode bestimmt.
Kreditorenbezogene Einrichtung
In dieser Einrichtung werden pro SQUEEZE Dokumentenklasse kreditorenspezifische Einstellungen vorgenommen. Dies wird für Kreditoren getan, welche vom eingestellten Mandanten-Standard abweichen.
Neben der Autovervollständigung von Positionen können hier auch abweichende Betrags- und Mengentoleranzen eingerichtet werden.
Liste
Karte
Autovervollständigen:
Bei Belegen ohne Bestellbezug kann das System sich die eingelesenen Positionen und die darauf angewandte Kontierung pro Kreditor merken und wieder abrufen. Hierfür gibt es drei Optionen, die gewählt werden können.
- Niemals: Deaktiviert die Funktion und blendet den Button in der Validierungsseite aus
- Manuell: Das Anwenden der Daten für die Autovervollständigung erfolgt manuell per Klick auf den Button "Autovervollständigen". Die Speicherung der Metadaten für die Autovervollständigung wird automatisch beim Abschluss des Validierungsprozesses ausgeführt
- Automatisch: Das Erstellen und Anwenden der Daten für die Autovervollständigung erfolgt automatisch
- Beim Erstellen des SQUEEZE Beleg werden die Einträge angewendet
- Beim Abschluss der Validierung werden die Einträge erstellt/aktualisiert
Automatische Validierung:
Aktivieren Sie diese Option, damit Squeeze for BC eingehende Belege automatisch validiert. Bitte beachten Sie, dass diese Funktion nur im Falle vollkommen plausibler Daten funktioniert.
Kontierungscode:
Gibt die Kontierungseinrichtung an, die bei der Durchführung der Kontierung im Validierungsprozess verwendet werden soll.
Bestellabgleich
Der Bestellabgleich dient zur automatisierten Überprüfung der ausgelesenen Positionen mit denen der noch offenen Bestellungen in Microsoft Dynamics 365 Business Central. In diesem FastTab werden die zulässigen Betrags- & Mengentoleranzen für den Abgleich eingerichtet. Zusätzlich kann festgelegt werden, ob der Abgleich gegen Bestellungen oder Lieferungen statt finden soll. Wenn "Daten ersetzen" aktiv ist, werden die Beträge und Beschreibungen der Positionen mit denen der Bestellung/Lieferung nach dem Abgleich ersetzt.
Kontierungseinrichtungen
Hier finden Sie die Kontierungseinrichtungen. Wenn Sie Standardkontierungen für bestimmte MwSt. Sätze haben, so können Sie die hier hinterlegen.
Sobald eine Kontierungseinrichtung mit Einrichtungszeilen angelegt und in einer Dokumentenklassen oder einer kreditorenbezogene Einrichtung hinterlegt wurde, wird diese automatisch heran gezogen.
Beim Importieren eines Beleges von Squeeze werden die erkannten MwSt. Sätze gegen die Einrichtungszeilen der hinterlegten Kontierungseinrichtung geprüft. Wenn passende Einträge gefunden werden, wird hierzu geprüft, ob Zeilen mit den hinterlegten Kontierungen angelegt werden dürfen. Im Standard Fall wird dies nur durchgeführt, wenn Squeeze keine Positionen liefert.
Zusätzlich kann eingerichtet werden, ob eine Kontierungseinrichtung automatisch für die Validierung angewendet werden soll.
Dies sollte in der Dokumentenklasseneinrichtung nicht als Standard gesetzt sein, da dies dann für alle Kreditoren und Belege gelten würde. Diese Option ergibt für einzelne Kreditoren mehr Sinn (Kreditorenbezogene Einrichtung).
Für die automatische Anwendung kann man zusätzlich aktivieren, dass alle Squeeze-Zeilen eines Dokuments mit den konfigurierten Kontierungseinrichtungszeilen überschrieben werden. ("Squeeze Zeilen überschreiben" anhaken)
Kontierungseinrichtung
Zu jedem Kontierungscode werden die Einrichtungszeilen separat verwaltet.
Hier werden die einzelnen MwSt. Sätze, zu denen Standardkontierungen gesetzt werden sollen, angelegt.
Pro MwSt. Satz setzt man im Anschluss die Kontierungsart.
Kontierungsart "Ein Konto"
Die Auswahl der Kontoart entspricht dem BC Standard:
Die Beschreibung kann nach Auswahl der Nummer beliebig angepasst werden.
Kontierungsart "Standardeinkaufscode"
Hier kann ein Standardeinkaufscode aus den wiederkehrenden Einkaufszeilen ausgewählt werden.
Feldzuordnung
In der Feldzuordnung wird das Standard-Mapping jeder Dokumentenklasse heruntergeladen. Diese feste Zuordnung gewährleistet einen reibungslosen Zuordnungsprozess von der Extraktion der Daten in Squeeze bis zur Erstellung eines Einkaufsbelegs.
Zuweisung von Metadaten
Werden in Squeeze Felder hinzugefügt, haben Sie an dieser Stelle die Möglichkeit, die enthaltenen Informationen direkt an definierte Felder des Einkaufsbelegs zu übertragen. Dieses Informationen sind in der Validierung nicht editierbar, sondern werden quasi "durchgeschleift".
nach Zuweisung:
Benutzerdefinierte Feldzuordnung
Möglicherweise möchten Sie in Ihrem Prozess immer gewisse Informationen abweichend von der Standard-Feldzuordnung in gewisse Felder schreiben. In dem folgenden Beispiel wird das durch Squeeze erkannte Leistungsdatum immer in das Feld "Buchungsdatum" geschrieben - zusätzlich zum Standardverhalten. Das Leistungsdatum bleibt also trotzdem gefüllt.
In der Dokumentenklassen-Einrichtung die Feldzuordnung öffnen:
Anschließend öffnen Sie die "Benutzerdefinierte Feldzuordnung":
Nehmen Sie dann die gewünschte Zuordnung vor:
- Auswahl des Squeeze-Feldes
- Auswahl des Validierungs-Feldes zu dem das Squeeze-Feld gemappt wird.
- Auswahl eines Zielfeldes im BC Standard EK-Beleg
In dieser Einrichtung kann man neue Squeeze Felder auf Validierungsfelder mappen (1+2). Alternativ kann man auch neue Validierungsfelder nur an den Workflow übergeben und das Zielfeld im EK-Beleg mit angeben (2+3). Zudem ist natürlich auch eine Kombination möglich, dass alle drei Optionen genutzt werden. Also eine Übertragung eines Feldes von der Beleglesung zur Validierung, über den Workflow hin zum Einkaufsbeleg.
Auf der Breeze Seite können diese Werte verarbeitet und auch zurück an BC übergeben werden.
Benutzerspezifische Einrichtung
In dieser Einrichtung werden benutzerspezifische Einstellungen vorgenommen. So haben Anwender die Möglichkeit, die App individuell auf ihre Arbeitsweise und Peripheriegeräte einzustellen.
Die Übersicht zeigt alle Benutzer und ihre jeweiligen Einstellungen. Beim Öffnen wird automatisch der aktuelle Benutzer angezeigt.
Viewer
- Nur externen Viewer verwenden: Wenn aktiviert, wird der Viewer ausschließlich extern (abgedockt) dargestellt. Dies ist insbesondere beim Arbeiten mit zwei Monitoren empfehlenswert. Der abgedockte Viewer aktualisiert sich bei einem Belegwechsel automatisch.
- Viewer Auflösung: Ermöglicht die Anpassung der Viewer-Auflösung. Die Optionen Hoch und Niedrig stehen zur Verfügung.
Validierung
- Zurück zur Liste nach Validierung: Wenn aktiviert, wird nach dem Abschluss der Validierung automatisch zur Belegübersicht zurück navigiert. Dies beschleunigt die Bearbeitung bei der sequenziellen Validierung mehrerer Belege.
- Validierungsdialog deaktivieren: Wenn aktiviert, wird der Bestätigungsdialog nach dem Abschluss der Validierung unterdrückt.
Squeeze Stammdatentabellen
Standardtabellen
Diese Stammdaten werden automatisch, sofern nicht deaktiviert, mit dem Squeeze Mandanten synchronisiert. Es ist nach wie vor notwendig, die Stammdaten initial hochzuladen.
Es werden bei den vorgegebenen Stammdatentabellen im Hintergrund die Events für OnInsert, OnModify und OnDelete überwacht und adhoc Änderungen gen Squeeze synchronisiert. Hierfür ist kein separater Job notwendig.
Das Feld "Verwendet externe Id" wird ab der Squeeze Version 2.13 unterstützt und bietet die Verwaltung der Squeeze Stammdaten aus einer Drittsoftware. In diesem Fall BC.
Stammdaten initial hochladen
Über die Funktion "Stammdaten erstmalig hochladen" werden alle Kreditoren und Kreditorenbankkonten, sowie der aktuelle Mandant und die relevanten Bestelldaten erstmalig an SQUEEZE übertragen.
Generische Stammdatentabellen
Um weitere Stammdaten gen Squeeze zu übertragen, welche nicht mit den Standard Stammdatentabellen überein stimmen, pflegt man diese in der generischen Stammdaten Tabellen Einrichtung.
Anlage der zu übertragenden Tabelle
Im Feld "BC Tabellennr." wird die zu übertragende Tabelle eingetragen oder über den Drilldown ausgewählt. Im Feld "Squeeze Tabellenname" kann dann die Bezeichnung angepasst werden. Im Feld "Synchronisierung aktiviert" wird festgelegt, ob diese Tabelle derzeit synchronisiert werden soll oder nicht.
Auswahl der zu übertragenden Felder
Über den Menüpunkt "Feldauswahl" erreichen Sie die Einrichtung.
Hier werden die Felder ausgewählt, welche synchronisiert werden sollen.
Erstellung der Squeeze Stammdatentabelle aus BC heraus
Nachdem eine BC Tabelle eingetragen und deren Felder für die Synchronisierung ausgewählt worden sind, kann nun eine neue Squeeze Tabelle aus BC heraus angelegt werden. Hierfür steht die Schaltfläche "Squeeze-Tabelle erstellen" zur Verfügung.
Nach der Erstellung wird in der Übersicht das Feld "Squeeze Tabellen-Id" gesetzt.
Auf der Squeeze Seite steht nun die neue Tabelle zur Verfügung.
Die ausgewählten Felder sind hier nun als Spalten automatisiert angelegt worden.
Synchronisation der Daten
Nach der Erstellung der Squeeze Tabelle wird der User gefragt, ob eine Synchronisierungsaufgabe erstellt werden soll.
Ist diese aktiv, so werden die Stammdaten automatisiert im eingerichteten Rhythmus übertragen. Alternativ können die Stammdaten auch manuell über die Schaltfläche "Jetzt synchronisieren" einmalig übertragen werden.
Löschen der Stammdatentabelle
Beim Löschen eines Listeneintrags wird gefragt, ob auch die Squeeze Stammdatentabelle mit gelöscht werden soll.
Sollte dies bestätigt werden, so wird die aus BC erstellte Squeeze-Tabelle unwiederbringlich entfernt.
Filterregeln
Über den Menüpunkt Filterregeln verwalten können Sie Filter definieren, die festlegen, welche Datensätze der BC-Tabelle an SQUEEZE synchronisiert werden sollen. So können Sie z. B. nur Datensätze eines bestimmten Typs oder mit einem bestimmten Status übertragen.
Spalten aktualisieren
Wenn sich die Feldauswahl einer generischen Stammdatentabelle geändert hat, können über die Aktion Spalten aktualisieren die Spalten in der SQUEEZE-Tabelle aktualisiert werden, ohne die gesamte Tabelle neu erstellen zu müssen.
Synchronisierungsstatus
Für jede generische Stammdatentabelle werden der Zeitpunkt der letzten Synchronisierung (Zuletzt synchronisiert) und ein eventueller Fehlertext (Letzter Synchronisierungsfehler) angezeigt. Dies erleichtert die Fehlerdiagnose bei Synchronisierungsproblemen.
Hinweis zu "Verwendet externe Id"
Das Feld Verwendet externe Id wird ab SQUEEZE Version 2.13 unterstützt. Wenn aktiviert, werden die Stammdaten in SQUEEZE über eine externe ID (aus Business Central) verwaltet. Dies ermöglicht eine bidirektionale Referenzierung und verhindert die doppelte Anlage von Stammdaten.
SQUEEZE
Grundsätzliche Einrichtung
Die SQUEEZE Seite muss ebenfalls für das Abholen der Dokumente aus Microsoft Dynamics Business Central vorbereitet werden.
Jede Dokumentenklasse welche von Microsoft Dynamics Business Central abgeholt werden soll, benötigt eine eigene Exportschnittstelle vom Typ "Pull". Zudem muss in Microsoft Dynamics Business Central in der Einrichtung für die SQUEEZE Dokumentenklassen die Dokumentenklassen ID, die Export Schnittstellen ID und die Stammdatentabellen ID hinterlegt werden.
Sofern nicht die neuste SQUEEZE for BC Version benutzt wird, müssen noch die folgenden Stapelklasseneigenschafen in dem SQUEEZE Mandanten gesetzt werden:
System Reset
Wird ein Squeeze System zurückgesetzt (z.B. im Rahmen von Tests), müssen folgende Schritte in Business Central berücksichtigt werden:
Importwarteschlange
Die Tabelle muss geleert werden. Dabei ist zu beachten, dass alle Filter entfernt werden, die in der Page gesetzt sind.
Rollencenter-Aktivitäten
SQUEEZE for BC erweitert das Rollencenter des Einkäufers um mehrere Aktivitätenkacheln, die einen Überblick über den aktuellen Bearbeitungsstatus der SQUEEZE-Belege geben.
SQUEEZE Aktivitäten
Diese Kacheln zeigen die Anzahl der SQUEEZE-Belege an, die eine Bearbeitung erfordern (offene Belege, heute erstellte Belege, etc.).
Zurückgestellte Belege
Diese Kacheln zeigen die Anzahl der zurückgestellten Belege, aufgeschlüsselt nach Zurückstellungsgrund:
- Gesamt zurückgestellte Belege: Die Gesamtanzahl aller zurückgestellten Belege.
- Kreditor existiert nicht: Belege, bei denen der Kreditor nicht im System gefunden wurde.
- Klärungsbedarf bzgl. der Leistung: Belege, bei denen Leistungsdetails geklärt werden müssen.
- Warten auf Wareneingang: Belege, die auf den Wareneingang warten.
Jede Kachel ist per Drilldown mit der gefilterten Squeeze Belegübersicht verknüpft.
Bestellabgleich-Aktivitäten
Diese Kacheln zeigen die Anzahl der Belege mit Abweichungen aus dem Bestellabgleich:
- Abweichungen insgesamt: Die Gesamtanzahl aller Belege mit identifizierten Abweichungen.
- Mengenabweichung: Belege mit Mengenunterschieden.
- Preisabweichung: Belege mit Preisunterschieden.
- Wareneingangsdatum-Abweichung: Belege mit abweichendem Wareneingangsdatum.
- Rabattabweichung: Belege mit Rabattunterschieden.
Navigation
Im Rollencenter stehen unter der Gruppe Squeeze zwei Navigationspunkte zur Verfügung:
- Aktueller Mandant: Öffnet die SQUEEZE Belegübersicht des aktuellen Mandanten.
- Mandantenübergreifend: Öffnet die mandantenübergreifende Belegansicht.
Über den Einrichtungsbereich des Rollencenters kann die SQUEEZE Einrichtung direkt aufgerufen werden.
Validierung
Sichtkontrolle der ausgelesenen Dokumente
SQUEEZE Beleg Übersicht
In der Belegübersicht werden alle Belege aufgelistet welche durch SQUEEZE ausgelesen worden sind.
Durch einen Doppelklick mit der Maus oder über Bearbeiten/Ansicht wird ein einzelner Beleg in der Validierungsansicht geöffnet.
Start
Belege jetzt herunterladen
Über diese Funktion wird die Belegabholung von SQUEEZE manuell ausgeführt. Wahlweise wird das über den entsprechenden Hintergrundjob gesteuert und durchgeführt.
Belege hochladen
Mit dieser Funktion können Sie Belege direkt über BC an ihr Squeeze System senden.
Navigation
Importwarteschlange
In diesem Menü wird eine Liste von SQUEEZE Belegen angezeigt, die bereit für den Import in die SQUEEZE for BC App sind. Durch das Ändern des Systemfilters ist es ebenfalls möglich, bereits importierte Belege einzusehen.
Mandanten-Belegübersicht
Öffnet eine mandantenübergreifende Ansicht aller Squeeze Belege.
Warteschlange
Öffnet eine Übersicht, die Ihnen Informationen zu den Belegen in der SQUEEZE Warteschlange des verbundenen Mandanten liefert.
Mandantenübergreifende Belegansicht
Die mandantenübergreifende Belegansicht bietet eine Gesamtübersicht aller SQUEEZE-Belege über sämtliche Business Central Mandanten hinweg, in denen SQUEEZE aktiviert ist.
Übersicht
Die Ansicht stellt für jeden Mandanten folgende Kennzahlen dar:
- Mandant: Der Name des jeweiligen Business Central Mandanten.
- Offene Belege: Die Anzahl der offenen SQUEEZE-Belege.
- Individuelle Verarbeitung: Die Anzahl der Belege im Status "Individuelle Verarbeitung".
- Überfällige Belege: Die Anzahl der überfälligen Belege.
- Dubletten: Die Anzahl der als Dublette markierten Belege.
- Abgelehnte Belege: Die Anzahl der abgelehnten Belege.
- Heute erstellte Belege: Die Anzahl der heute erstellten Belege.
- Meine offenen Belege: Die Anzahl der dem aktuellen Benutzer zugewiesenen Belege.
Zusätzlich werden die Ergebnisse des Bestellabgleichs mandantenübergreifend zusammengefasst:
- Abweichungen insgesamt: Gesamtanzahl der Belege mit Bestellabgleich-Abweichungen.
- Preisabweichung / Mengenabweichung / Wareneingangsdatum-Abweichung / Rabattabweichung: Aufschlüsselung nach Abweichungstyp.
Navigation
Jede Kennzahl ist als Drilldown ausgeführt: Durch einen Klick auf einen Wert wird die entsprechend gefilterte Belegübersicht des jeweiligen Mandanten in einem neuen Tab geöffnet.
Aktualisierung
Die Daten werden asynchron im Hintergrund geladen und aktualisieren sich automatisch alle 60 Sekunden. Über die Aktion Daten aktualisieren kann eine manuelle Aktualisierung ausgelöst werden.
Die mandantenübergreifende Belegansicht ist aus der Belegübersicht über die Aktion Mandanten-Belegübersicht oder über das Rollencenter (Squeeze > Mandantenübergreifend) erreichbar.
Importwarteschlange
Die Importwarteschlage ist eine Mittelschicht, die SQUEEZE Belege in die entsprechenden Zielmandaten importiert - der Zielmandant muss mit dem aktuellen BC Mandanten (wichtig: Der Name (Primärschlüssel) ist ausschlaggebend, nicht der Anzeigename) in dem die Belege heruntergeladen werden, übereinstimmen. Wurde kein Zielmandant erkannt, werden die Belege für die Validierung in dem eingerichteten Fallback Mandanten erstellt.
Navigation
Importwarteschlangen-Einrichtung
Fallback Mandant
Gibt den Wert des Fallback Mandanten an. In diesen Mandanten werden Belege importiert, die in der Importwarteschlange einen leeren Zielmandanten aufweisen.
Zeitspanne für Warnung (Stunden)
Gibt die Zeitspanne an, nach der eine Warnung angezeigt werden soll, wenn es unverarbeitete Einträge gibt.
Start
Unverarbeitete Datensätze verarbeiten
Importpuffer
Über die Aktion Importpuffer kann eine Seite geöffnet werden, in der SQUEEZE Beleg-IDs manuell eingetragen werden können. Dies ist nützlich, wenn ein einzelner Beleg gezielt aus SQUEEZE heruntergeladen werden soll, z. B. wenn ein Beleg nicht automatisch abgeholt wurde.
Systemfilter
Standardmäßig werden in der Importwarteschlange nur unverarbeitete Einträge des aktuellen Mandanten angezeigt. Über den Systemfilter können auch bereits verarbeitete Einträge sowie Einträge anderer Mandanten eingesehen werden.
Die Spalte Zielmandant wird rot hervorgehoben, wenn der Zielmandant vom aktuellen Mandanten abweicht. Dies weist darauf hin, dass der Beleg für einen anderen Mandanten bestimmt ist.
SQUEEZE Belegvalidierung
Die Belegvalidierung ist der Hauptarbeitsbereich der Anwendung. Hier werden die ausgelesenen Belege vom Anwender überprüft, fehlende Informationen ergänzt und bestätigt.
Menü
Start
Feldtraining öffnen
Öffnet das lieferantenspezifische Feldtraining.
Positionstraining öffnen
Öffnet das lieferantenspezifische Positionstraining.
Beleg neu erstellen
Sendet den Beleg erneut in den Extraktionsschritt des verbundenen SQUEEZE Mandanten. Dort wird das Ausleseergebnis anhand der aktuellen Stammdaten und Trainings neu bewertet und im Anschluss erneut zur Abholung bereit gestellt.
Dokument aufteilen
Ruft die die Belegtrennung auf. Diese wird verwendet, falls ein Lieferant mehrere Rechnungen in einer PDF gesandt hat.
Autovervollständigen
Vervollständigt die Kontierung der Positionen automatisch mit den zuletzt validierten Positionsdaten des Kreditoren. Diese Funktion steht nur für Belege ohne Bestellbezug zur Verfügung und muss explizit in der Dokumentenklassen Einrichtung aktiviert werden.
Bestellabgleich
Öffnet den Bestellabgleich.
Validieren
Schließt den Validierungsprozess des Belegs ab.
Doublettenprüfung
Wenn ein neuer Beleg (z.B. eine Eingangsrechnung) ins System importiert wird, prüft SQUEEZE automatisch, ob dieses Dokument bereits vorhanden ist. Ziel ist es, eine doppelte Erfassung zu verhindern.
Voraussetzungen
Bevor die eigentliche Prüfung startet, müssen zwei Bedingungen erfüllt sein:
- Das Dokument muss einen gültigen Einkaufsbelegart haben (z.B. Rechnung, Gutschrift)
- Der Kreditor (Lieferant) muss bekannt sein — ohne Lieferantennummer ist keine Prüfung möglich
Außerdem findet die gesamte Prüfung nur statt, wenn eine Belegnr. (z.B. die Rechnungsnummer des Lieferanten) vorhanden ist. Ohne diese Referenz kann kein Abgleich erfolgen.
Prüfschritte (in dieser Reihenfolge)
Die Prüfung vergleicht immer die Kombination aus drei Feldern:
- Einkaufsbelegart (z.B. Rechnung)
- Belegnr (z.B. die externe Rechnungsnummer des Lieferanten)
- Kreditorennummer (welcher Lieferant)
Mit dieser Kombination wird in vier Bereichen nacheinander gesucht:
- Bereits gebuchte Belege — Gibt es schon einen gebuchten Posten mit derselben Rechnungsnummer von diesem Lieferanten?
- Andere importierte SQUEEZE-Belege— Wurde dieselbe Rechnung bereits als anderes Dokument importiert und wartet noch auf Verarbeitung?
- Offene Einkaufsbelege — Existiert bereits ein offener (noch nicht gebuchter) Einkaufsbeleg in Business Central mit denselben Daten?
- Corebelege — Ist das Dokument bereits im übergeordneten DXP-System vorhanden (z.B. Breeze Interface)?
Was passiert bei einem Treffer?
Sobald in einem der vier Schritte ein bestehendes Dokument gefunden wird, gilt das neue Dokument als Duplikat. Die Prüfung stoppt sofort, und das Dokument wird entsprechend markiert. Die weiteren Schritte werden dann nicht mehr durchlaufen.
Beleg ablehnen
Diese Aktion erlaubt es Ihnen, einen Beleg abzulehnen. Dieser wird dann, wahlweise mit einem zusätzlichen Kommentar, in einem speziellen Status "Abgelehnt" abgespeichert - nicht jedoch gelöscht.
Im Anschluss kann noch eine e-Mail an den Lieferanten gesandt werden.
Hierfür ist ein Standardkonto in der Einrichtung "E-Mail-Konten" anzulegen und als Standard im "E-Mail-Szenario Einrichtung" zu setzen.
Ist dies eingerichtet, wird das BC E-Mail Modul geöffnet. Hier wird der Bemerkungstext der Ablehnung, die Rechnungsnummer, sowie der Absender/Bearbeiter der Validierung vorausgefüllt.
Navigation
Dimensionen
Hier rüber erreichen Sie das Dimensionsmenü um Dimensionen für den Belegkopf zu hinterlegen.
Viewer
Externen Viewer öffnen
Hier rüber wird der Viewer abgedockt. Dies ermöglicht das Arbeiten auf zwei Monitoren.
Aktionen
Dokument verschieben
Hier rüber wird ein Beleg in einen anderen Mandanten verschoben.
Anhänge herunterladen
Hier rüber laden Sie die Anhänge des Belegs herunter. Sobald das Herunterladen abgeschlossen wurde, werden diese in der Infobox Anhänge angezeigt. Sie haben die Möglichkeit, das Herunterladen der Anhänge automatisch durchführen zu lassen - diese Einstellung nehmen Sie bitte in der Dokumentenklassen Einrichtung vor.
Fasttabs
Beleg
In diesem Bereich werden die Belegkopf-Informationen sowie der SQUEEZE Viewer angezeigt.
Kopffelder
Diese Felder werden mit den Ergebnissen aus der Beleglesung vorbelegt. Der Anweder prüft diese und korrigiert, bzw. reichert sie mit weiteren Daten an und vervollständigt so das Leseergebnis. Über die drei Punkte wird die Fundstelle des jeweiligen Leseergebnisses im Viewer hervorgehoben.
Viewer
Auf der rechten Seite wird der SQUEEZE Viewer angezeigt. Hierbei handelt es sich nicht um ein PDF, sondern um eine eingebundene Webkomponente, welche hier aus der Validierung ferngesteuert wird. Sie dient zur bildlichen Darstellung des Belegs und zum hervorheben von Fundstellen gelesener Werte. Weiterhin wird hier auch das lieferantenspezifische Feldtraining durchgeführt.
Zeilen
In diesem Bereich werden die ausgelesenen Positionen angezeigt. Der Anweder prüft diese und korrigiert, bzw. reichert sie mit weiteren Daten an und vervollständigt so das Leseergebnis.
Sollte das Leseergebnis bei Rechnungen mit Bestellbezug nicht ausreichen, so können die Bestell-/Wareneingangszeilen direkt importiert werden.
Bei Rechnungen ohne Bestellbezug können Positionen aus den MwSt. Raten und Kopfbeträgen generiert werden. Eine Zeile pro MwSt. Rate. Hierfür wird die Kontierungseinrichtung aus der Dokumentenklasse heran gezogen.
Dimensionen
Hier werden die Shortcut Dimensionen 1 & 2 des Belegs angezeigt.
SQUEEZE Details
Hier werden SQUEEZE spezifische Beleginformationen angezeigt.
Infoboxen
Die jeweiligen Infoboxen werden nur situationsbedingt angezeigt.
Plausibilitätseinträge
Hier werden alle zu klärende Themen für eine erfolgreiche Validierung aufgelistet.
Metadatenboxen
Die Metadatenzuordnung wird nur angezeigt, wenn vom Standard abweichende zusätzliche Felder von SQUEEZE übertragen worden sind.
Metadatenzuordnung Kopffelder
Hier werden zusätzliche Felder aus SQUEEZE aufgelistet, welche nicht zu der Standardzuordnung der Kopffelder gehören.
Metadatenzuordnung Positionsfelder
Hier werden zusätzliche Felder aus SQUEEZE aufgelistet, welche nicht zu der Standardzuordnung der Positionen gehören.
Bestellabgleichsboxen
Die Bestellabgleichsboxen werden nur angezeigt, wenn eine oder mehrere Bestellnummern auf dem Beleg erkannt worden sind.
Bestellabgleich-Info (Preise)
Hier wird für die ausgewählte Zeile der Preisvergleich angezeigt. Verglichen werden die Ergebnisse von SQUEEZE, der Lieferung, der Bestellung und der aktuellen Zeile.
Bestellabgleich-Info (Mengen)
Hier wird für die ausgewählte Zeile der Mengenvergleich angezeigt. Verglichen werden die Ergebnisse von SQUEEZE, der Lieferung, der Bestellung und der aktuellen Zeile.
Anhänge
Diese Infobox wird nur angezeigt, wenn die Anhänge zuvor heruntergeladen worden sind (das kann auf Wunsch auch automatisch nach der Belegerstellung passiert - siehe Dokumentenklassen Einrichtung. Über die drei Punkte lassen sich die Anhänge wieder entfernen.
Beleg zurückstellen / Zurückstellung entfernen
Über die Aktion Beleg zurückstellen kann ein Beleg temporär zurückgestellt werden. In dem sich öffnenden Dialog muss ein Grund ausgewählt werden:
- Kreditor existiert nicht: Der Kreditor wurde im System nicht gefunden.
- Klärungsbedarf bzgl. der Leistung: Die Liefer- oder Leistungsdetails müssen geklärt werden.
- Warten auf Wareneingang: Der Wareneingang steht noch aus.
Zusätzlich kann eine freie Notiz hinterlegt werden. Zurückgestellte Belege können nicht validiert werden, bis die Zurückstellung über Zurückstellung entfernen aufgehoben wird.
Zurückgestellte Belege werden im Rollencenter in eigenen Aktivitätenkacheln nach Grund aufgeschlüsselt dargestellt.
Ablehnung zurücknehmen
Wurde ein Beleg bereits abgelehnt, kann die Ablehnung über die Aktion Ablehnung zurücknehmen wieder aufgehoben werden. Der Beleg kehrt dann in den vorherigen Status zurück.
Beleg verschieben
Über die Aktion Beleg verschieben (im Menü unter Aktionen) kann ein Beleg in einen anderen Mandanten verschoben werden. Der Beleg wird im aktuellen Mandanten gelöscht und im Zielmandanten neu erstellt.
Kreditor erstellen/finden
Über die Aktion Kreditor erstellen/finden kann anhand der erkannten Textfelder (Name, Adresse, USt-ID etc.) ein passender Kreditor im System gesucht oder ein neuer Kreditor angelegt werden.
Fehlendes Bankkonto erstellen
Über die Aktion Fehlendes Bankkonto erstellen kann ein Kreditorbankkonto aus der erkannten IBAN angelegt werden, sofern die IBAN auf dem Beleg erkannt wurde, jedoch kein passendes Bankkonto beim Kreditor hinterlegt ist.
Kontierungscode anwenden
Über die Aktion Kontierungscode anwenden in den Zeilen können alle Positionen gelöscht und anhand einer konfigurierten steuerlichen Kontierungseinrichtung automatisch neue Zeilen generiert werden. Diese Funktion steht über die Kontierungseinrichtungen zur Verfügung.
Viewer-Modi
Der SQUEEZE Viewer in der Belegvalidierung unterstützt drei Darstellungsmodi:
- Belegübersicht: Zeigt den gesamten Beleg im Viewer an.
- Positionsfokus: Fokussiert den Viewer auf den Positionsbereich des Belegs.
- Abgedockt: Öffnet den Viewer in einem separaten Browserfenster (siehe auch "Externer Viewer").
Feldalternativen
Wenn SQUEEZE bei der Beleglesung mehrere mögliche Werte für ein Feld erkennt (z. B. mehrere mögliche Kreditorennummern), werden diese als Feldalternativen bereitgestellt. Die Feldalternativen können über die Infobox eingesehen werden. Der Anwender kann so den passenden Wert auswählen.
Lieferantenspezifisches Training
Das Training stellt eine wesentliche Optimierungs-Komponente der Verarbeitung dar.
Sofern Daten nicht eindeutig durch das System erkannt werden, können lieferanten-spezifische Trainings angewendet werden, welche den Automatisierungsgrad bei der Erfassung der Rechnungen erhöhen.
Wenn der Trainingsmodus gestartet wird, können alle relevanten Felder für ein Training ausgewählt werden.
Es können beliebig viele Trainings pro Lieferant und pro Rechnungsfeld angelegt werden.
Externe Rechnungsnummern lassen sich in der Regel nicht inhaltlich im System prüfen, da keine Daten zur Überprüfung bestehen. Dieses Feld ist z.B. ideal für Trainings.
Das Trainingsfenster wird innerhalb des Viewers am unteren Bildrand eingeblendet.
Kopffeld Training
Trainieren eines Feldes
Nachdem die Trainingsfunktion gestartet wurde, ist das zu trainierende Feld auszuwählen.
Nachdem das entsprechende Feld ausgewählt wurde, ist der Anker zu definieren.
Mit Anker ist in diesem Fall der Bezugsbegriff gemeint. In diesem Falle der auf der jeweiligen Rechnung angebrachte Begriff für die externe Belegnummer. Der Ankerbegriff ist mit der rechten Maustaste auf dem Dokument im Viewer zu markieren und wird dann gelb hinterlegt.
Anschließend ist das Feld „Wert“ im Aktionsbereich anzuklicken und dann der Wert, der gesucht werden soll. Dieser ist ebenfalls mit der rechten Maustaste zu markieren. Ist der gesuchte Wert kein zusammenhängender Wert, kann auch mit der rechten Maustaste ein beliebig großer Bereich markiert werden, um alle gewünschten Informationen auszulesen. Ist die Information angegeben, kann das Training über „Trainieren“ gespeichert werden.
Das System erzeugt einen „regulären Ausdruck“ – dieser kann von geschultem Fachpersonal oder IT-lern jederzeit noch optimiert werden. Z.B. können Leerzeichen ignoriert werden, da diese selten auch im ERP System / in der Buchung mit angegeben werden.
Testen und Prüfen der vorhandenen Trainings
Mit „Testen“ wird eine Übersicht aller bisherigen Kopffeld-Trainings angezeigt. Die Ergebnisse werden direkt mit ausgegeben. Durch einen Doppelklick auf einen Eintrag wird der Anker und der Wert in dem Viewer hervorgehoben.
Entfernen eines Trainings
Um ein Training wieder zu entfernen wird die Übersicht der vorhandenen Trainings geöffnet und der zu entfernende Eintrag markiert. Mit der Entfernen-Taste "Entf" wird der Eintrag gelöscht.
Positionsfeld Training
Trainieren einer Spalte
Nachdem die Trainingsfunktion gestartet wurde, ist das zu trainierende Feld und die dazugehörige Spalte auszuwählen.
Nachdem dies ausgewählt wurde, ist die Region zu definieren.
Diese ist so zu wählen, dass Sie möglichst die gesamte Spalte eines Feldes abdeckt. Die Region ist mit der rechten Maustaste auf dem Dokument im Viewer zu markieren und wird dann gelb hinterlegt. Hierbei ist zu beachten, dass sich keine Regionen mit bereits trainierten Regionen überschneiden sollten.
Sind die Information angegeben, kann das Training über „Trainieren“ gespeichert werden.
Testen und Prüfen der vorhandenen Trainings
Mit „Testen“ wird eine Übersicht aller bisherigen Positionsfeld-Trainings angezeigt. Durch einen Doppelklick auf einen Eintrag wird der jeweils trainierte Bereich angezeigt.
Entfernen eines Trainings
Um ein Training wieder zu entfernen wird die Übersicht der vorhandenen Trainings geöffnet und der zu entfernende Eintrag markiert. Mit der Entfernen-Taste "Entf" wird der Eintrag gelöscht.
Dokument Aufteilen
Die Trennfunktion ist hauptsächlich für E-Mail-Rechnungen gedacht. Wenn Lieferanten sich nicht an die Vorgabe der E-Mail-Rechnungs-Zustellung halten (pro PDF Datei eine Rechnung). Es ist aber auch möglich die Seiten eines PDF neu zu sortieren.
In dem neuen Fenster wird ein Dialog gestartet, um die Belege voneinander zu trennen und so aus einem Beleg mehrere zu machen.
Auf der linken Seite werden alle Seiten des original PDFs aufgelistet. In der Mitte ist der Bereich für die Neuerstellung und Rechts sieht man die aktuell ausgewählte Seite.
Um einen Beleg aufzuteilen werden die zu einer Rechnung dazugehörigen Seiten einzeln entweder per Maus mit Drag&Drop oder per Pfeil-Taste der Tastatur in den mittleren Bereich übertragen. Dort kann man auch die Reihenfolge der Seiten korrigieren.
Ist das Rechnungsdokument korrekt separiert, kann die Erzeugung eines neuen Einzelbelegs mit „Dokument erzeugen“ gestartet werden. Der neue Beleg wird direkt von SQUEEZE ausgelesen, verarbeitet und sobald er bereit steht auch in der Übersichtsliste bereitgestellt. Dieser Vorgang wird solange wiederholt bis der original Beleg komplett aufgeteilt worden ist.
Bestell- & Wareneingangsabgleich
Der Bestell- & Wareneingangsabgleich prüft die ausgelesenen Belegpositionen und vergleicht diese mit allen Bestell- & Wareneingangszeilen anhand der ausgelesenen Bestellnummern des Belegs.
Der Bestellabgleich kann nur geöffnet werden, wenn SQUEEZE eine oder mehrere Bestellnummern vom Beleg ausgelesen hat oder wenn manuell eine (im System hinterlegte) Bestellnummer in dem Validierungs-Kopffeld eingetragen wurde.
Dieser Vergleich wird nach der Abholung des Belegs aus SQUEEZE automatisch durchgeführt. Der Anwender hat die Möglichkeit diesen Vergleich auch manuell durchzuführen oder zu korrigieren.
Menü
Zuweisen
Zugewiesene Zeilen werden durch einen grünen Haken dargestellt .
Zuweisen
Hiermit wird die ausgewählte Bestell-/Lieferzeile der ausgewählten SQUEEZE Belegzeile zugewiesen.
Automatisch zuweisen
Hiermit wird allen SQUEEZE Belegzeilen die passende Bestell-/Lieferzeile zugewiesen. Hierfür muss im oberen Bereich die Bestellung/Lieferung selbst ausgewählt werden.
Zuweisung entfernen
Nicht zugewiesene Zeilen werden durch ein rotes Ausrufezeichen dargestellt .
Ausgewählte Zuweisung entfernen
Hiermit wird die Zuweisung der ausgewählten Zeile entfernt.
Alle Zuweisungen entfernen
Hiermit werden alle Zuweisungen entfernt.
Anwenden
Ausgewählte Zeile anwenden
Hiermit wird die Zuweisung der ausgewählten Zeile angewendet. Fehlende Informationen werden aus der Bestell-/Lieferzeile ergänzt. Diese Änderung wird hierdurch auch umgehend an die Validierungszeile übertragen.
Zugewiesene Zeilen anwenden
Hiermit wird die Zuweisung aller zugewiesenen Zeilen angewendet. Fehlende Informationen werden aus den zugewiesenen Bestell-/Lieferzeile ergänzt. Diese Änderungen werden hierdurch auch umgehend an die Validierungszeilen übertragen.
Bereiche
Bestellnummer
Hier wird die derzeit zu vergleichende Bestellnummer angezeigt. Sollten mehrere Bestellnummern ausgelesen worden sein, so kann über die drei Punkte die entsprechende Liste geöffnet werden.
Bestell- & Lieferungen
in diesem Bereich werden die Bestellung und alle Ihre Zeilen, sowie alle dazugehörigen Lieferungen und deren Zeilen aufgelistet.
SQUEEZE Belegzeilen
In diesem Bereich werden alle ausgelesenen Positionen des SQUEEZE Belegs aufgelistet.
Bestell-/ Wareneingangszeilen manuell importieren
Holen der Positionen aus Bestellung / Wareneingang
Menü
Hinzufügen zur Importvorschau
Hiermit werden alle ausgewählten Zeilen in die Importvorschau übernommen.
Ausgewählte Zeilen werden durch einen grünen Haken dargestellt .
Ausgewählte Vorschauzeile löschen
Hiermit werden alle ausgewählten Zeilen aus der Importvorschau entfernt.
Importvorschau übernehmen
Hiermit werden alle Zeilen aus der Importvorschau in den zu validierenden Beleg übernommen. Sie haben die Wahl ob diese Zeilen die SQUEEZE Positionen ersetzen oder hinten angehängt werden sollen.
Bereiche
Bestellnummer
Hier wird die ausgelesene Bestellnummer angezeigt. Sollten mehrere Bestellnummern ausgelesen worden sein, so kann über die drei Punkte die entsprechende Liste geöffnet werden.
Bestell- & Lieferungen
in diesem Bereich werden die Bestellung und alle Ihre Zeilen, sowie alle dazugehörigen Lieferungen und deren Zeilen aufgelistet.
Importvorschau
In diesem Bereich werden alle ausgewählten Positionen aufgelistet.
Externer Viewer
Um das Arbeiten mit dem Viewer zu vereinfachen, kann der eingebettete Viewer abgedockt und so auf einem zweiten Bildschirm genutzt werden.
Sämtliche Viewer Funktionen, wie z.B. das Highlighting der Kopf- und Positionsdaten, sowie die Trainingsfunktionen des Viewers werden weiterhin unterstützt.
Damit der abgedockte Viewer auch bei einem Belegwechsel aktiv bleibt und sich selbstständig aktualisiert, muss in der benutzerspezifischen Einrichtung das Feld "Nur externen Viewer verwenden" gesetzt werden.
Belege hochladen
SQUEEZE for BC bietet die Möglichkeit, Belege direkt aus Business Central an das verbundene SQUEEZE-System zu senden.
Belege hochladen über die Belegübersicht
In der SQUEEZE Belegübersicht steht die Aktion Belege hochladen zur Verfügung. Beim Aufruf wird die zu verwendende Dokumentenklasse abgefragt. Anschließend öffnet sich die Upload-Seite.
Squeeze Dateiupload
Auf der Upload-Seite können Dateien per Drag & Drop in den Ablagebereich gezogen werden. Es können mehrere Dateien gleichzeitig abgelegt werden.
Über die Aktion Dateien hochladen werden alle abgelegten Dateien an den SQUEEZE Mandanten übertragen. Nach dem erfolgreichen Upload wird jede Datei mit einem Häkchen markiert.
Beim Schließen der Seite wird geprüft, ob alle abgelegten Dateien hochgeladen wurden. Sollte mindestens eine Datei nicht hochgeladen worden sein, erscheint eine entsprechende Warnung.
SQUEEZE Warteschlange
Die SQUEEZE Warteschlange bietet eine Echtzeitübersicht über den Verarbeitungsstatus aller Belege in der SQUEEZE-Pipeline des verbundenen Mandanten.
Übersicht
Die Warteschlange zeigt für jeden Verarbeitungsschritt die Anzahl der darin befindlichen Belege an:
- Fehler: Belege, bei denen ein Fehler aufgetreten ist (rot hervorgehoben). Über den Drilldown wird die SQUEEZE Web-Oberfläche geöffnet.
- Neue Dokumente: Belege, die sich im initialen Verarbeitungsschritt befinden.
- Bildaufbereitung: Belege, die aktuell bildtechnisch aufbereitet werden.
- Barcode Extraktion: Belege, bei denen Barcodes ausgelesen werden.
- Texterkennung (OCR): Belege, bei denen die Texterkennung durchgeführt wird.
- Klassifizierung: Belege, die einer Dokumentenklasse zugeordnet werden.
- Extraktion: Belege, bei denen die Datenextraktion (Beleglesung) durchgeführt wird.
- Export: Belege, die bereit zur Abholung durch Business Central sind.
- Verarbeitet: Bereits verarbeitete Belege.
Nicht-leere Schritte werden fett dargestellt. Die Ansicht aktualisiert sich automatisch alle 5 Sekunden.
Aktionen
- Belege jetzt herunterladen: Löst eine manuelle Abholung von Belegen aus SQUEEZE aus.
- Beleg hochladen: Ermöglicht das Hochladen eines Belegs an das SQUEEZE-System.
Die Warteschlange ist aus der SQUEEZE Belegübersicht über die Aktion Warteschlange erreichbar.
Viewer im Ziel-Beleg
Ab der neuesten Version kann der SQUEEZE Viewer auch in den resultierenden Zielbelegen (Einkaufsrechnungen und Einkaufsbestellungen) angezeigt werden. Dadurch können Anwender den ursprünglich gescannten Beleg jederzeit einsehen, ohne zum SQUEEZE-Beleg zurückkehren zu müssen.
Aktivierung
Die Funktion wird in der SQUEEZE Einrichtung im FastTab Viewer über den Schalter Viewer im Ziel-Beleg aktiviert.
Funktionsweise
Wenn die Funktion aktiviert ist, erscheint der SQUEEZE Viewer als Infobox (FactBox) auf den folgenden Seiten:
- Einkaufsrechnung: Der Viewer zeigt den ursprünglich gescannten Beleg an, aus dem die Rechnung erstellt wurde.
- Einkaufsbestellung: Bei Auftragsbestätigungen zeigt der Viewer den zugehörigen gescannten Beleg an.
Der Viewer unterstützt dabei alle gewohnten Funktionen, wie z. B. das Hervorheben von Fundstellen. Auch der abgedockte Modus wird unterstützt.
Hinweis
Die Verknüpfung zwischen Zielbeleg und SQUEEZE-Beleg wird automatisch über den DEXPRO Core hergestellt. Der Viewer wird nur angezeigt, wenn für den jeweiligen Einkaufsbeleg ein zugehöriger SQUEEZE-Beleg existiert.
Plausibilitätsprüfungen
Die Plausibilitätsprüfung ist ein zentraler Bestandteil der Belegvalidierung. Sie stellt sicher, dass alle relevanten Daten plausibel und vollständig sind, bevor ein Beleg weiterverarbeitet wird. Die Ergebnisse werden in der Infobox Plausibilitätseinträge angezeigt.
Kopffeld-Prüfungen
- Kreditor existiert / nicht gesperrt: Der angegebene Kreditor muss im System vorhanden sein und darf nicht gesperrt sein (optional: Gesperrtstatus "Zahlung" kann über "Gesperrten Lieferanten (Zahlung) ignorieren" in der Dokumentenklassen Einrichtung übersprungen werden).
- Pflichtfelder: Belegdatum, Buchungsdatum, Belegnummer und Belegart müssen ausgefüllt sein.
- Buchungsdatum: Das Buchungsdatum muss in einem zulässigen Buchungszeitraum liegen (kann über "Buchungsdatum nicht prüfen" deaktiviert werden).
- IBAN-Prüfung: Wenn eine IBAN erkannt wurde, wird geprüft, ob beim Kreditor ein passendes Bankkonto hinterlegt ist (kann über "IBAN nicht prüfen" deaktiviert werden).
- USt-ID-Prüfung: Wenn eine USt-ID erkannt wurde, wird geprüft, ob diese mit der hinterlegten USt-ID des Kreditors übereinstimmt (kann über "USt-ID nicht prüfen" deaktiviert werden).
- Doublettenprüfung: Es wird geprüft, ob bereits ein Beleg mit derselben Belegnummer und demselben Kreditor existiert.
- Währungscode: Der angegebene Währungscode muss im System vorhanden sein.
- Bestellnummer: Wenn eine Bestellnummer angegeben ist, muss die zugehörige Bestellung im System existieren.
Betragsüberprüfungen
- Kopfbetragsprüfung: Es wird geprüft, ob die Netto-, Steuer- und Gesamtbeträge rechnerisch korrekt sind (kann über "Kopfbetragsprüfung deaktivieren" abgeschaltet werden).
- Zeilenbetragsvergleich: Die Summe der Zeilenbeträge wird mit den Kopfbeträgen verglichen (kann über "Zeilenbetragsvergleich deaktivieren" abgeschaltet werden).
- Kopfsteuerprüfung: Es wird geprüft, ob der Steuerbetrag zum Nettobetrag und Steuersatz passt (kann über "Kopfsteuerprüfung deaktivieren" abgeschaltet werden).
Zeilenprüfungen
- Buchungsgruppen: Für jede Zeile wird geprüft, ob die erforderlichen MwSt.-Buchungsgruppen und allgemeinen Buchungsgruppen existieren.
- Artikel: Wenn ein Artikel zugewiesen ist, muss dieser im System vorhanden sein.
- Mengeneinheit: Die angegebene Mengeneinheit muss für den zugewiesenen Artikel gültig sein.
- Lagerort: Wenn ein Lagerort angegeben ist, muss dieser existieren (kann über "Lagerortprüfung deaktivieren" abgeschaltet werden).
- Dimensionen: Die Dimensionswerte in Kopf und Zeilen werden auf Gültigkeit geprüft.
- Projektdaten: Wenn Projektdaten (Projektnr., Projektaufgabennr.) zugewiesen sind, wird deren Existenz und Gültigkeit geprüft.
Konfiguration
Die einzelnen Plausibilitätsprüfungen können in der Dokumentenklassen Einrichtung unter dem Abschnitt Plausibilitätsprüfung individuell deaktiviert werden. Dies ermöglicht es, die Validierung an die jeweiligen Geschäftsprozesse anzupassen.
Auftragsbestätigungen
Neben Einkaufsrechnungen und Gutschriften unterstützt SQUEEZE for BC auch die Verarbeitung von Auftragsbestätigungen. Diese Dokumentenklasse ermöglicht es, eingehende Auftragsbestätigungen von Lieferanten automatisiert zu erfassen und mit bestehenden Einkaufsbestellungen abzugleichen.
Verarbeitung
Auftragsbestätigungen durchlaufen denselben Verarbeitungsprozess wie Rechnungen (SQUEEZE-Extraktion, Import, Validierung). Die folgenden Besonderheiten gelten:
- Pflicht-Bestellzuweisung: Im Gegensatz zu Rechnungen muss bei Auftragsbestätigungen mindestens eine Zeile einer Bestellzeile zugewiesen sein, bevor die Validierung abgeschlossen werden kann.
- Zugesagtes Wareneingangsdatum: Das vom Lieferanten bestätigte Lieferdatum wird auf Zeilenebene erfasst und als "Zugesagtes Wareneingangsdatum" übernommen.
- Kein Wareneingangs-Abgleich: Auftragsbestätigungen können nur gegen Bestellungen abgeglichen werden, nicht gegen Wareneigänge (Lieferungen).
Bestellabgleich bei Auftragsbestätigungen
Der Bestellabgleich bei Auftragsbestätigungen prüft zusätzlich folgende Bedingungen:
- Das zugesagte Wareneingangsdatum darf nicht leer sein.
- Die bestätigte Menge und der bestätigte Einzelpreis dürfen nicht Null sein.
- Abweichungen zwischen bestätigten und bestellten Werten (Menge, Preis, Rabatt, Lieferdatum) werden in den Bestellabgleich-Infoboxen hervorgehoben.
Toleranzen
Im Gegensatz zu Rechnungen steht bei Auftragsbestätigungen zusätzlich die Toleranz Wareneingangsdatum in der Dokumentenklassen- und der kreditorenbezogenen Einrichtung zur Verfügung. Diese definiert als Datumsformel, wie weit das bestätigte Lieferdatum vom erwarteten abweichen darf (z. B. 2D für zwei Tage).
Einrichtung
Um Auftragsbestätigungen zu verarbeiten, muss eine eigene Dokumentenklasse vom Typ Auftragsbestätigung in SQUEEZE und in der Dokumentenklassen Einrichtung in Business Central eingerichtet werden.
Extension Entwicklung
In diesem Kapitel werden wichtige Integration Events und Beispiele aufgeführt, die bei der Entwicklung einer Extension für SQUEEZE for BC helfen.
Wichtig:
Anpassungen dürfen nur durch entsprechend geschulte Berater/Entwickler durchgeführt werden. Diese befinden sich außerdem immer außerhalb des Standard-Supports.
Squeeze-Ursprungsanhang anpassen
Übersicht
Das OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment Integration Event ermöglicht es Drittanbieter-Entwicklern, Dokumentenanhang-Datensätze anzupassen, bevor sie während des SQUEEZE-Anhang-Verarbeitungsworkflows modifiziert werden. Ein Ursprungsanhang ist der relevante Anhang, der zur Erstellung eines Belegs führt (z.B. die Rechnung des Lieferanten).
Event-Deklaration
[IntegrationEvent(false, false)]
local procedure OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment(var DocumentAttachment: Record "DXP Document Attachment")
begin
end;
Event-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
| DocumentAttachment | Record "DXP Document Attachment" (var) |
Der Dokumentenanhang-Datensatz, der modifiziert werden soll. Als Referenz übergeben, wodurch Änderungen möglich sind. |
Wann wird dieses Event ausgelöst?
Dieses Event wird während der SaveAttachments-Prozedur ausgelöst, wenn:
- Ein Anhang von SQUEEZE verarbeitet wird
- Der Anhang als Ursprungsdatei identifiziert wird (
IsOriginFile = true) - Das System den Ursprungsdateinamen und das
DXP Is Origin FileFlag gesetzt hat - Kurz vor dem
DocumentAttachment.Modify(true)-Aufruf
Anwendungsfälle
Dieses Integration Event ist nützlich für:
- Benutzerdefiniertes Füllen von Feldern: Setzen zusätzlicher benutzerdefinierter Felder im Dokumentenanhang
- Dateinamen-Transformation: Anwenden benutzerdefinierter Namenskonventionen oder Formatierung
- Metadaten-Erweiterung: Hinzufügen benutzerdefinierter Metadaten oder Tags zu Anhängen
- Validierungslogik: Implementierung benutzerdefinierter Validierung vor dem Speichern des Datensatzes
- Integrationsanforderungen: Vorbereitung von Daten für externe Systemintegrationen
Implementierungsbeispiel
Dateinamen vor Modifikation ändern
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment', '', false, false)]
local procedure OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment(var DocumentAttachment: Record "DXP Document Attachment")
var
CoreDocument: Record "DXP Document";
SQZDocumentHeader: Record "DXP SQZ Document Header";
Vendor: Record Vendor;
NewFileName: Text[250];
VendorPrefix: Text[50];
begin
// Get the core document using the document attachment's Document No.
if not CoreDocument.Get(DocumentAttachment."Document No.") then
exit;
// Check if the core document has a linked SQUEEZE document
if IsNullGuid(CoreDocument."Linked-to Record Id") then
exit;
// Get the SQZ Document Header using the SystemId from Linked-to Record Id
if not GetSQZDocumentHeaderFromRecordId(CoreDocument."Linked-to Record Id", SQZDocumentHeader) then
exit;
// Check if Buy-from Vendor No. is populated
if SQZDocumentHeader."Buy-from Vendor No." = '' then
exit;
// Get the vendor record
if not Vendor.Get(SQZDocumentHeader."Buy-from Vendor No.") then
exit;
// Create vendor prefix from Search Name (fallback to Name if Search Name is empty)
if Vendor."Search Name" <> '' then
VendorPrefix := Vendor."Search Name"
else
VendorPrefix := Vendor.Name;
// Clean the vendor prefix (remove invalid filename characters and limit length)
VendorPrefix := CleanFilenameText(VendorPrefix, 30);
// Check if vendor prefix already exists in filename to avoid duplicates
if DocumentAttachment."File Name".StartsWith(VendorPrefix + '_') then
exit;
// Create new filename with vendor prefix
NewFileName := VendorPrefix + '_' + DocumentAttachment."File Name";
// Update the attachment filename
DocumentAttachment."File Name" := NewFileName;
end;
local procedure GetSQZDocumentHeaderFromRecordId(LinkedRecordId: Guid; var SQZDocumentHeader: Record "DXP SQZ Document Header"): Boolean
var
RecRef: RecordRef;
SystemIdFieldRef: FieldRef;
begin
// Method 1: Try to get the record directly if LinkedRecordId is actually a SystemId
if SQZDocumentHeader.GetBySystemId(LinkedRecordId) then
exit(true);
// Method 2: If that fails, we need to find the record another way
// This assumes the Linked-to Record Id might be stored differently
SQZDocumentHeader.Reset();
SQZDocumentHeader.SetRange(SystemId, LinkedRecordId);
exit(SQZDocumentHeader.FindFirst());
end;
local procedure CleanFilenameText(InputText: Text; MaxLength: Integer): Text
var
CleanText: Text;
begin
// Remove invalid filename characters
CleanText := DelChr(InputText, '=', '<>|"/\:*?');
// Replace spaces with underscores for better filename compatibility
CleanText := CleanText.Replace(' ', '_');
// Limit length
CleanText := CopyStr(CleanText, 1, MaxLength);
exit(CleanText);
end;
Wichtige Überlegungen
Datenintegrität
- Der
DocumentAttachment-Datensatz wird als Referenz übergeben, daher werden alle Änderungen gespeichert - Berücksichtigen Sie Feldlängenbegrenzungen beim Ändern von Textfeldern
Performance
- Halten Sie die Verarbeitung schlank, da dieses Event für jeden Ursprungsdatei-Anhang aufgerufen wird
- Erwägen Sie das Zwischenspeichern häufig verwendeter Daten
Fehlerbehandlung
- Implementieren Sie ordnungsgemäße Fehlerbehandlung, um zu verhindern, dass der Anhang-Speichervorgang fehlschlägt
- Verwenden Sie try-Funktionen für riskante Operationen
Verwandte Events
OnAfterSaveAttachment: Wird ausgelöst, nachdem jeder Anhang vollständig gespeichert wurde.- Erwägen Sie die Verwendung dieses alternativen Events, wenn Sie Aktionen nach dem Speichern des Datensatzes durchführen müssen.
Fehlerbehebung
Wenn Ihr Event Subscriber nicht ausgelöst wird:
- Testen Sie speziell mit Ursprungsdateien (Nicht-Ursprungsdateien lösen dieses Event nicht aus)
Abweichende Verwendung der SQUEEZE Anhänge
Im Folgenden wird kurz erläutert, wie die durch SQUEEZE for BC heruntergeladenen Anhänge für ein Szenario verwendet werden können, das von der vorgesehenen Verwendung abweicht.
Nach der Erstellung des Einkaufsbeleges aus dem validierten SQUEEZE Beleg haben Sie die Möglichkeit, die Anhänge abzugreifen (sofern diese im Vorfeld heruntergeladen wurden).
// Set IsHandled to true and implement your code
// Do not forget to deactivate "Transfer attachments to target document" in the Document Class Setup
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Mgt.", 'OnBeforeTransferCoreAttachmentsToStandardDocument', '', false, false)]
local procedure DXPDocMgtOnBeforeTransferCoreAttachmentsToStandardDocument(Document: Record "DXP Document"; var IsHandled: Boolean)
begin
IsHandled := true;
HandleCoreAttachmentsAccordingToYourNeeds(Document, IsHandled);
end;
procedure HandleCoreAttachmentsAccordingToYourNeeds(Document: Record "DXP Document"; var IsHandled: Boolean)
var
CoreAttachments: Record "DXP Document Attachment";
InStr: InStream;
begin
CoreAttachments.SetRange("Document No.", Document."No.");
CoreAttachments.IsEmpty() then
exit;
CoreAttachments.FindSet();
repeat
CoreAttachments.Calcfields(Attachment);
CoreAttachments.Attachment.CreateInStream(InStr);
// Here you can handle the file stream according to your needs
[...]
until CoreAttachments.Next() = 0;
end;
Anpassung der Dateinamen von Anhängen nach der Validierung
Überblick
Diese Anleitung zeigt, wie Entwickler die Dateinamen von Anhängen in DEXPRO SQUEEZE anpassen können. Das Event OnBeforeAddLineToDocumentJObj wird nach der Plausibilitätsprüfung ausgeführt, sodass alle Belegdaten vollständig validiert und verfügbar sind.
Verfügbares Event
OnBeforeAddLineToDocumentJObj
Für Rechnungen/Gutschriften: Codeunit 70954657 "DXP SQZ P. Inv/Crdt Memo Impl."
Für Bestellbestätigungen: Codeunit 70954658 "DXP SQZ P. Order Conf. Impl."
Wann aufgerufen: Nach Header-Verarbeitung, vor Zeilen-Verarbeitung, nach Plausibilitätsprüfung
Implementierungsbeispiele
Beispiel 1: Einfacher Kreditorenprefix für Rechnungen/Gutschriften
codeunit 50100 "Custom Invoice Filename"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure OnBeforeAddLineToDocumentJObjInvoice(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
CustomizeAttachmentFilenames(DocHeader);
end;
local procedure CustomizeAttachmentFilenames(DocHeader: Record "DXP SQZ Document Header")
var
DocumentAttachment: Record "DXP Document Attachment";
VendorPrefix: Text;
NewFileName: Text[1024];
begin
// Beenden, wenn keine Kreditorinformationen vorhanden
if DocHeader."Buy-from Vendor No." = '' then
exit;
// Kreditorenprefix erstellen
VendorPrefix := DocHeader."Buy-from Vendor No." + '_';
// Alle Anhänge für dieses Dokument bearbeiten
DocumentAttachment.Reset();
DocumentAttachment.SetRange("Document No.", DocHeader."Core Document No.");
if DocumentAttachment.FindSet(true) then
repeat
// Überspringen, wenn Prefix bereits vorhanden
if not DocumentAttachment."File Name".Contains(VendorPrefix) then begin
// Neuen Dateinamen mit Prefix erstellen
NewFileName := VendorPrefix + DocumentAttachment."File Name";
// Aktualisieren
DocumentAttachment."File Name" := CopyStr(NewFileName, 1, MaxStrLen(DocumentAttachment."File Name"));
DocumentAttachment.Modify(true);
end;
until DocumentAttachment.Next() = 0;
end;
}
Beispiel 2: Bestellbestätigungen - Kreditorenprefix
codeunit 50101 "Custom Order Conf Filename"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Order Conf. Impl.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure OnBeforeAddLineToDocumentJObjOrderConf(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
CustomizeAttachmentFilenames(DocHeader);
end;
local procedure CustomizeAttachmentFilenames(DocHeader: Record "DXP SQZ Document Header")
var
DocumentAttachment: Record "DXP Document Attachment";
VendorPrefix: Text;
NewFileName: Text[1024];
begin
// Beenden, wenn keine Kreditorinformationen vorhanden
if DocHeader."Buy-from Vendor No." = '' then
exit;
// Kreditorenprefix erstellen
VendorPrefix := DocHeader."Buy-from Vendor No." + '_';
// Alle Anhänge für dieses Dokument bearbeiten
DocumentAttachment.Reset();
DocumentAttachment.SetRange("Document No.", DocHeader."Core Document No.");
if DocumentAttachment.FindSet(true) then
repeat
// Überspringen, wenn Prefix bereits vorhanden
if not DocumentAttachment."File Name".Contains(VendorPrefix) then begin
// Neuen Dateinamen mit Prefix erstellen
NewFileName := VendorPrefix + DocumentAttachment."File Name";
// Aktualisieren
DocumentAttachment."File Name" := CopyStr(NewFileName, 1, MaxStrLen(DocumentAttachment."File Name"));
DocumentAttachment.Modify(true);
end;
until DocumentAttachment.Next() = 0;
end;
}
Beispiel 3: Beide Dokumenttypen - Verschiedene Prefixe für Quelldateien
codeunit 50102 "Advanced Filename Handling"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure OnBeforeAddLineToDocumentJObjInvoice(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
CustomizeFilenamesWithSourceHandling(DocHeader);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Order Conf. Impl.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure OnBeforeAddLineToDocumentJObjOrderConf(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
CustomizeFilenamesWithSourceHandling(DocHeader);
end;
local procedure CustomizeAttachmentFilenames(DocHeader: Record "DXP SQZ Document Header")
var
DocumentAttachment: Record "DXP Document Attachment";
VendorPrefix: Text;
NewFileName: Text[1024];
begin
// Beenden, wenn keine Kreditorinformationen vorhanden
if DocHeader."Buy-from Vendor No." = '' then
exit;
// Kreditorenprefix erstellen
VendorPrefix := DocHeader."Buy-from Vendor No." + '_';
// Alle Anhänge für dieses Dokument bearbeiten
DocumentAttachment.Reset();
DocumentAttachment.SetRange("Document No.", DocHeader."Core Document No.");
if DocumentAttachment.FindSet(true) then
repeat
// Überspringen, wenn Prefix bereits vorhanden
if not DocumentAttachment."File Name".Contains(VendorPrefix) then begin
// Neuen Dateinamen mit Prefix erstellen
NewFileName := VendorPrefix + DocumentAttachment."File Name";
// Aktualisieren
DocumentAttachment."File Name" := CopyStr(NewFileName, 1, MaxStrLen(DocumentAttachment."File Name"));
DocumentAttachment.Modify(true);
end;
until DocumentAttachment.Next() = 0;
end;
}
Praktische Hinweise
Verfügbare Daten zur Event-Zeit:
DocHeader."Buy-from Vendor No."- Kreditorennummer (validiert)DocHeader."Document Date"- BelegdatumDocHeader."Document Reference"- BelegnummerDocHeader."Core Document No."- Verknüpfung zu Anhängen- Alle anderen Belegfelder sind verfügbar
Beispielresultate:
- Original:
"Rechnung_2024_001.pdf" - Mit Kreditorenprefix:
"VEND001_Rechnung_2024_001.pdf" - Quelldatei:
"ORIGINAL_VEND001_Rechnung_2024_001.pdf"
Best Practices:
- Duplikatprüfung: Immer prüfen, ob Prefix bereits vorhanden
- Längenvalidierung: Neue Dateinamen dürfen max. 1024 Zeichen haben
Hinzufügen eines Feldes in der Validierung (ab Version 2.10)
Im Folgenden wird anhand einer Beispielextension dargestellt, wie man als Entwickler Felder in der Validierung hinzufügen kann (hier: Dokumentenklasse Rechnung/Gutschrift).
Optionale Integration Events inkl. beispielhafter Prozeduren:
codeunit 50100 EventSubs
{
//
// [If you want to perform plausibility checks on the newly added header field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoHeaderPlausibilityChecks', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnBeforeDoHeaderPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocHeader."Customer No.");
end;
//
// [If you want to perform plausibility checks on the newly added line field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoLinePlausibilityChecks', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnAfterDoLinePlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; DocLine: Record "DXP SQZ Document Line"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocLine."Customer No.");
end;
[TryFunction]
local procedure CustomerExists(CustomerNo: Code[20])
var
Customer: Record Customer;
begin
Customer.Get(CustomerNo);
end;
local procedure CheckCustomer(var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt."; CustomerNo: Code[20]): Boolean
begin
if CustomerNo = '' then
exit(false);
if not CustomerExists(CustomerNo) then begin
PlausibilityCheck.AddPlausibilityCheckEntry(GetLastErrorText(), Page::"Customer List");
exit(false);
end;
exit(true);
end;
}
Table Extensions:
SQUEEZE 4 BC
tableextension 50100 "SQZ Doc. Header Ext." extends "DXP SQZ Document Header"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
tableextension 50101 "SQZ Doc. Line Ext." extends "DXP SQZ Document Line"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
tableextension 50102 "Purchase Header Ext." extends "Purchase Header"
{
fields
{
field(50100; "DXP Customer No."; Code[20])
{
DataClassification = CustomerContent;
TableRelation = Customer;
Caption = 'DEXPRO Customer No.';
}
}
}
Page Extensions:
SQUEEZE 4 BC
pageextension 50100 "SQZ Document Ext." extends "DXP SQZ Document v2"
{
layout
{
addafter(BuyFromVendorInternal)
{
field("Customer No. Internal"; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
//The following code is optional. It is used to highlight a recognized value in the Squeeze Viewer
trigger OnAssistEdit()
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
addafter(BuyFromVendorExternal)
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
//The following code is optional. It is used to highlight a recognized value in the Squeeze Viewer
trigger OnAssistEdit()
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
}
local procedure MarkField(AppFldNo: Integer; FieldVal: Variant; DocHeader: Record "DXP SQZ Document Header")
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
ViewerResident := GetViewerResident();
ApiMgt.MarkField(AppFldNo, FieldVal, ViewerResident, DocHeader);
end;
}
pageextension 50101 "SQZ Document Sf. Ext." extends "DXP SQZ Document Subform"
{
layout
{
addafter("No.")
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
}
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
pageextension 50102 "Purchase Invoice Ext." extends "Purchase Invoice"
{
layout
{
addafter("Buy-from Vendor No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
pageextension 50103 "Purchase Inv. Sf Ext." extends "Purch. Invoice Subform"
{
layout
{
addafter("No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
Implementierung eines benutzerdefinierten, automatischen Bestellabgleichs
Einführung
Der automatische Bestellabgleich ist ein wichtiger Bestandteil der Dokumentenverarbeitung in Squeeze for Business Central. Im Standard vergleicht das System eingehende Belege mit vorhandenen Bestellungen und Wareneingängen. Diese Dokumentation zeigt Ihnen, wie Sie diesen Abgleichsprozess um Ihre eigenen Belegarten erweitern können.
Die Standardimplementierung verwendet einen dreistufigen Prozess:
- Sammeln relevanter Belegnummern basierend auf Geschäftsregeln
- Für jede gefundene Belegnummer wird ein detaillierter Abgleich durchgeführt
- Im Anschluss werden die von Squeeze ausgelesenen Positionen um die gefundenen Daten angereichert
Diesen bewährten Ansatz werden wir in der folgenden, beispielhaften Implementierung beibehalten.
Integrationspunkt
Der zentrale Integrationspunkt ist das OnBeforePerformAutomaticOrdermatch-Event in Codeunit 70954632 "DXP SQZ Document Mgt.". Dieses Event wird nach der Erstellung von Kopf- und Positionsdaten aufgerufen.
[IntegrationEvent(false, false)]
local procedure OnBeforePerformAutomaticOrdermatch(
DocHeader: Record "DXP SQZ Document Header";
var OrderNoList: List of [Code[20]];
var IsHandled: Boolean)
Parameter
DocHeader: Der Dokumentenkopf mit den zu vergleichenden DatenOrderNoList: Eine Liste von Belegnummern für den AbgleichIsHandled: Steuert, ob die Standardverarbeitung übersprungen werden soll
Implementierungsbeispiel
Technische Umsetzung
1. Erweiterung des Dokumententyp-Enums
Zunächst erweitern wir die möglichen Dokumententypen um unseren eigenen Typ:
enumextension 50100 "Custom Order Match Doc. Type" extends "DXP Order Match Document Type"
{
value(50000; "Custom")
{
Caption = 'Custom Document';
}
}
2. Implementierung der Abgleichslogik
Der zentrale Punkt unserer Implementierung ist eine Codeunit, die den Abgleichsprozess steuert. Integrationspunkt ist :
//codeunit 50100 "Custom Document Matching"
//{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforePerformAutomaticOrdermatch', '', false, false)]
local procedure OnBeforePerformAutomaticOrdermatch(
DocHeader: Record "DXP SQZ Document Header";
var OrderNoList: List of [Code[20]];
var IsHandled: Boolean)
var
CustomSourceDoc: Record "Custom Source Document";
CustomDocNo: Code[20];
begin
// Take control of the matching process and prevent standard processing
IsHandled := true;
// Find potential matching documents
CustomSourceDoc.SetRange("Vendor No.", DocHeader."Buy-from Vendor No.");
// Add your specific document status or type filters
CustomSourceDoc.SetRange("Document Type", CustomSourceDoc."Document Type"::Order);
CustomSourceDoc.SetRange(Status, CustomSourceDoc.Status::Released);
// Add matching document numbers to the list
if CustomSourceDoc.FindSet() then
repeat
CustomDocNo := CustomSourceDoc."No.";
if IsDocumentEligibleForMatching(CustomSourceDoc, DocHeader) then
if not OrderNoList.Contains(CustomDocNo) then
OrderNoList.Add(CustomDocNo);
until CustomSourceDoc.Next() = 0;
// Process all collected documents
ProcessMatchingDocuments(DocHeader, OrderNoList);
end;
local procedure IsDocumentEligibleForMatching(
CustomSourceDoc: Record "Custom Source Document";
DocHeader: Record "DXP SQZ Document Header"): Boolean
begin
// Implement business rules for document selection
// For example:
if CustomSourceDoc."Document Date" > DocHeader."Document Date" then
exit(false);
if CustomSourceDoc."Currency Code" <> DocHeader."Currency Code" then
exit(false);
// Check for open lines that can be matched
if not HasOpenLinesToMatch(CustomSourceDoc) then
exit(false);
exit(true);
end;
local procedure HasOpenLinesToMatch(CustomSourceDoc: Record "Custom Source Document"): Boolean
var
CustomSourceLine: Record "Custom Source Line";
begin
CustomSourceLine.SetRange("Document No.", CustomSourceDoc."No.");
CustomSourceLine.SetFilter("Outstanding Quantity", '>0');
exit(not CustomSourceLine.IsEmpty());
end;
//}
3. Verarbeitung der gefundenen Belege
Nach dem Sammeln der relevanten Belegnummern erfolgt der eigentliche Abgleich:
local procedure ProcessMatchingDocuments(
DocHeader: Record "DXP SQZ Document Header";
OrderNoList: List of [Code[20]])
var
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary;
OrderNo: Code[20];
begin
foreach OrderNo in OrderNoList do begin
// Get matching entries for current document
GetMatchEntries(OrderNo, TempMatchEntry, DocHeader);
if not TempMatchEntry.IsEmpty() then
// Try to find and assign matching lines
TryMatchDocumentLines(TempMatchEntry, DocHeader);
end;
end;
local procedure GetMatchEntries(
DocumentNo: Code[20];
var TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary;
DocHeader: Record "DXP SQZ Document Header")
var
CustomSourceLine: Record "Custom Source Line";
begin
TempMatchEntry.Reset();
TempMatchEntry.DeleteAll();
// Get lines from custom document
CustomSourceLine.SetRange("Document No.", DocumentNo);
if CustomSourceLine.FindSet() then
repeat
// Create match entry for each relevant line
CreateMatchEntry(CustomSourceLine, TempMatchEntry);
until CustomSourceLine.Next() = 0;
end;
local procedure CreateMatchEntry(
CustomSourceLine: Record "Custom Source Line";
var TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary)
begin
TempMatchEntry.Init();
TempMatchEntry."Document Type" := "DXP Order Match Document Type"::Custom;
TempMatchEntry."Document No." := CustomSourceLine."Document No.";
TempMatchEntry."Document Line No." := CustomSourceLine."Line No.";
TempMatchEntry."No." := CustomSourceLine."Item No.";
TempMatchEntry.Quantity := CustomSourceLine.Quantity;
TempMatchEntry."Direct Unit Cost" := CustomSourceLine."Unit Price";
TempMatchEntry."Line Amount" := CustomSourceLine.Amount;
TempMatchEntry.Insert();
end;
Die Matching-Logik im Detail
Der eigentliche Abgleich der Belegzeilen erfolgt nach definierten Geschäftsregeln:
local procedure TryMatchDocumentLines(
var TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary;
DocHeader: Record "DXP SQZ Document Header")
var
DocLine: Record "DXP SQZ Document Line";
MatchSetup: Record "Custom Match Setup";
HasCustomSetup: Boolean;
begin
// Get configuration
MatchSetup.Get();
// Process each potential match entry
if TempMatchEntry.FindSet() then
repeat
DocLine.Reset();
DocLine.SetRange("Document No.", DocHeader."No.");
DocLine.SetRange("Buy-from Vendor No.", TempMatchEntry."Buy-from Vendor No.");
DocLine.SetFilter("Allocated Document Line No.", '%1', 0); // Only unallocated lines
// Try matching strategies in order of precision
if TryExactMatch(DocLine, TempMatchEntry) then
CheckTolerancesAndAllocate(TempMatchEntry, DocLine, MatchSetup)
else
if TryItemReferenceMatch(DocLine, TempMatchEntry) then
CheckTolerancesAndAllocate(TempMatchEntry, DocLine, MatchSetup)
else
if TryDescriptionMatch(DocLine, TempMatchEntry) then
CheckTolerancesAndAllocate(TempMatchEntry, DocLine, MatchSetup)
else
if TryBasicValuesMatch(DocLine, TempMatchEntry) then
CheckTolerancesAndAllocate(TempMatchEntry, DocLine, MatchSetup);
until TempMatchEntry.Next() = 0;
end;
local procedure TryExactMatch(
var DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary): Boolean
begin
DocLine.SetRange(Type, TempMatchEntry.Type);
DocLine.SetFilter("No.", '%1|%2', TempMatchEntry."No.", TempMatchEntry."Item Reference No.");
DocLine.SetRange("SQZ Quantity", TempMatchEntry.Quantity);
exit(not DocLine.IsEmpty());
end;
local procedure TryItemReferenceMatch(
var DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary): Boolean
begin
DocLine.SetRange(Type); // Clear previous filters
DocLine.SetRange("Item Reference No.", TempMatchEntry."Item Reference No.");
exit(not DocLine.IsEmpty());
end;
local procedure TryDescriptionMatch(
var DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary): Boolean
begin
DocLine.SetRange("Item Reference No."); // Clear previous filter
DocLine.SetFilter("SQZ Description", '@*' + TempMatchEntry.Description + '*');
exit(not DocLine.IsEmpty());
end;
local procedure TryBasicValuesMatch(
var DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary): Boolean
begin
DocLine.SetRange("SQZ Description"); // Clear previous filter
DocLine.SetRange("SQZ Quantity", TempMatchEntry.Quantity);
DocLine.SetRange("SQZ Unit Price", TempMatchEntry."Direct Unit Cost");
exit(not DocLine.IsEmpty());
end;
local procedure CheckTolerancesAndAllocate(
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary;
var DocLine: Record "DXP SQZ Document Line";
MatchSetup: Record "Custom Match Setup")
begin
DocLine.FindFirst(); // We know there is at least one line
if IsMatchWithinTolerances(DocLine, TempMatchEntry, MatchSetup) then
AssignMatchData(DocLine, TempMatchEntry);
end;
local procedure IsMatchWithinTolerances(
DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary;
MatchSetup: Record "Custom Match Setup"): Boolean
var
QtyTolerance: Decimal;
AmountTolerance: Decimal;
begin
QtyTolerance := MatchSetup."Quantity Tolerance";
AmountTolerance := MatchSetup."Amount Tolerance";
if Abs(DocLine."SQZ Quantity" - TempMatchEntry.Quantity) > QtyTolerance then
exit(false);
if Abs(DocLine."SQZ Unit Price" - TempMatchEntry."Direct Unit Cost") > AmountTolerance then
exit(false);
exit(true);
end;
local procedure AssignMatchData(
var DocLine: Record "DXP SQZ Document Line";
TempMatchEntry: Record "DXP SQZ Order Match Entry" temporary)
begin
// Assign the matched data to the document line
DocLine.Validate("Allocated Document Type", "DXP Order Match Document Type"::Custom);
DocLine.Validate("Allocated Document No.", TempMatchEntry."Document No.");
DocLine.Validate("Allocated Document Line No.", TempMatchEntry."Document Line No.");
DocLine.Validate("Allocated Quantity", TempMatchEntry.Quantity);
DocLine.Validate("Allocated Unit Price", TempMatchEntry."Direct Unit Cost");
DocLine.Validate("Allocated Line Amount", TempMatchEntry."Line Amount");
DocLine.Validate("Allocated Line Discount %", TempMatchEntry."Line Discount %");
DocLine.Modify(true);
end;
Bei Fragen zur Implementierung stehen wir Ihnen gerne zur Verfügung.
Implementierung einer neuen, generischen Dokumentenklasse
SQUEEZE → Core → Ihre Verarbeitung
Dieser Leitfaden ist bewusst fokussiert und pipeline‑orientiert: Er zeigt, wie Belegdaten aus SQUEEZE heruntergeladen, in Warteschlangen verarbeitet und in DEXPRO Core persistiert werden – und an welcher Stelle sich eine Drittanbieter‑Extension einklinkt.
Begriff: In diesem Leitfaden meint „SQUEEZE‑App“ die Business‑Central‑Erweiterung, die mit der SQUEEZE API verbunden ist und den Import nach DEXPRO Core steuert.
Annahmen:
- Drittanbieter‑Entwickler arbeiten typischerweise mit veröffentlichten Symbolen, nicht mit dem gesamten Quellcode.
- Die SQUEEZE‑App übernimmt Herunterladen + Importwarteschlange + Erstellung des Core‑Belegs sowie die rudimentäre Erstellung des SQUEEZE‑Belegs unter Berücksichtigung der Feldzuordnung, sobald die Einrichtung abgeschlossen ist.
- Ihre Extension übernimmt die Fachlogik, nachdem das Core‑Dokument existiert: Quell‑Datensätze erstellen bzw. erweitern, validieren, „Processed JSON“ erzeugen und optional ein eigenes Zielobjekt oder einen eigenen Beleg erstellen.
1) Der Ende‑zu‑Ende‑Ablauf SQUEEZE → Core
Sobald Dokumentklasse und Einrichtung konfiguriert sind, läuft die Importpipeline der SQUEEZE‑App typischerweise so ab:
DXP Document Classerweitern und Ihre Implementierung binden:DXP ISource Document.- Dokumentenklassen‑Einrichtung für diese Klasse konfigurieren.
- Beim Validieren von
DXP SQZ Document Class IDholt die SQUEEZE‑App automatisch die benötigten Einrichtungswerte aus SQUEEZE (z. B.DXP SQZ Export Interface IDundDXP SQZ Line Table ID) und füllt sie.
- Beim Validieren von
- Der Job der SQUEEZE‑App ruft
DXP SQZ API Mgt.DownloadDocumentData()auf. Auch via "Belege herunterladen" aufrufbar- Dabei werden neue Einträge in
DXP SQZ Import Queueangelegt (Dokument‑ID + Zielmandant).
- Dabei werden neue Einträge in
- Die SQUEEZE‑App ruft
DXP SQZ Import Queue Mgt.TransferImportQueueEntries()auf.- Dabei wird die Orchestrierungs‑Codeunit
DXP Sqz Create Documentfür die Einträge in der Importwarteschlange ausgeführt.
- Dabei wird die Orchestrierungs‑Codeunit
DXP SQZ API Mgt.CreateCoreAndSQUEEZEDocument(DocClass, DocumentId)lädt das vollständige JSON.- Es wird
DXP Document Mgt.AddDocument(DocClass, DocumentId, RawJson, …)aufgerufen. - Ergebnis: Ein
DXP Document‑Datensatz existiert. Status =Imported,JSON Rawist gefüllt.
- Es wird
- Die SQUEEZE‑App ruft Ihre Implementierung
ISourceDocument.CreateSource(Document)auf.- Ab hier beginnt Ihre Implementierung.
Nach Schritt 6 haben Sie:
- Ein Core‑Container‑Dokument (
DXP Document). - Ein SQUEEZE‑Dokument auf Seite der SQUEEZE‑App.
- Ihre Source‑Datensätze sollten existieren, sobald
CreateSourceerfolgreich abgeschlossen ist.
2) Was Sie implementieren (Interfaces)
Quell‑Vertrag, also Squeeze Seite: DXP ISource Document
Das implementieren Sie, um:
- Ihre editierbaren Source‑Datensätze aus
DXP Document.JSON Rawzu erstellen - Source‑Datensätze zu validieren
- „Processed JSON“ zu erzeugen und an Core‑Processing zu übergeben
Ziel‑Vertrag, also Zielbeleg: DXP IDocument Processing
Das implementieren Sie, wenn Core aus dem „Processed JSON“ einen eigenen Ziel‑Datensatz (Ihre eigene Tabelle / Ihr eigenes Dokument) erstellen/aktualisieren soll.
3) Schritt 1 — Dokumentklasse definieren und Quell‑Implementierung zuweisen
Erstellen Sie eine Enum‑Extension und binden Sie Ihre Source‑Implementierung:
enumextension 50100 "MY Document Class Ext." extends "DXP Document Class"
{
value(50100; "MY Generic Document")
{
Caption = 'My Generic Document';
Implementation = "DXP ISource Document" = "MY Source Document Impl.";
}
}
4) Schritt 2 — Dokumentenklassen‑Einrichtung konfigurieren (damit die Importwarteschlange gefüllt wird)
Konfigurieren Sie in der Dokumentenklassen‑Einrichtung für Ihre neue Dokumentklasse die SQUEEZE‑spezifischen Felder.
Wichtig:
- Das Validieren von
DXP SQZ Document Class IDtriggert das automatische Laden der erforderlichen Konfiguration aus SQUEEZE (z. B.DXP SQZ Export Interface IDundDXP SQZ Line Table ID). - Falls der Abruf fehlschlägt, werden diese API‑abgeleiteten Felder wieder geleert.
Ergebnis: Die SQUEEZE‑App kann DownloadDocumentData() ausführen und Einträge in DXP SQZ Import Queue für Ihre Klasse anlegen.
5) Schritt 3 — Feldzuordnung sicherstellen (heruntergeladene Zuordnung + Ihre Standardwerte)
Die SQUEEZE‑App kann den Feldkatalog des angeschlossenen Squeeze Mandanten herunterladen und in Core‑Mapping‑Tabellen persistieren (pro Dokumentklasse).
Ihre Rolle als Dokumentklassen‑Implementierer:
- Standard‑Feldzuordnung „Squeeze Field Name → AL Field No.“ via
InitFieldMapping(...)bereitstellen. - Alternativ Felder über die Zuordnungs‑Pages mappen (Benutzerdefinierte Feldzuordnung).
5.1 InitFieldMapping implementieren (eigenständiges Beispiel)
codeunit 50101 "MY Source Document Impl." implements "DXP ISource Document"
{
procedure InitFieldMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer])
var
Header: Record "DXP SQZ Document Header";
Line: Record "DXP SQZ Document Line";
begin
Clear(HeaderMapping);
Clear(LineMapping);
// Header fields
HeaderMapping.Add('vendorNo', Header.FieldNo("Buy-from Vendor No."));
HeaderMapping.Add('documentDate', Header.FieldNo("Document Date"));
HeaderMapping.Add('postingDate', Header.FieldNo("Posting Date"));
HeaderMapping.Add('reference', Header.FieldNo("Document Reference"));
// Line fields
LineMapping.Add('description', Line.FieldNo(Description));
LineMapping.Add('quantity', Line.FieldNo(Quantity));
LineMapping.Add('unitPrice', Line.FieldNo("Direct Unit Cost"));
end;
// other interface methods omitted here...
}
5.2 Validierungs‑Schalter beim Zuweisen von Feldern: App‑Feld validieren
Wenn die SQUEEZE‑App oder Ihre Quell‑Erstelllogik JSON‑Werte in „App-/Quellfelder“ schreibt, können Sie steuern, ob der OnValidate‑Trigger ausgeführt wird.
In DXP Custom Field Mapping:
Validate App Field= App‑Feld während des Assignments validieren.Validate(Ziel) = Validierung beim Transfer in das Ziel‑Feld ausführen.
Nutzen Sie das z. B. wenn Erweiterungsfelder Business‑Logik in OnValidate haben oder wenn Sie bewusst trigger‑frei (performanter) zuweisen wollen.
6) Schritt 4 — Source‑Datensätze in CreateSource erstellen
CreateSource(Document) wird von der SQUEEZE‑App unmittelbar nach DXP Document Mgt.AddDocument(...) aufgerufen, sobald der Core‑Container‑Datensatz existiert.
Minimale Verantwortlichkeiten:
DXP Document.JSON Rawlesen.- SQUEEZE‑Source‑Header/Lines erstellen (
DXP SQZ Document Header/DXP SQZ Document Line). - Core‑Dokument mit dem SQUEEZE‑Source‑Header via
UpdateDocumentAfterTransferverknüpfen.
Optional (empfohlen, wenn Sie Gleichwertigkeit der Funktionen zu den Standard‑SQUEEZE‑Dokumentklassen möchten): 4) Anhänge herunterladen, wenn DXP Download Attachments aktiv ist. 5) Automatische Validierung ausführen, wenn für das Dokument aktiviert.
6.1 Beispiel: SQUEEZE‑Header + Lines mit den generischen Helpern erstellen
Was die Helper machen (damit Sie es nicht doppelt implementieren):
-
SqzDocumentMgt.CreateSQUEEZEDocHeader(Document, DocHeader, RawJson)- Erstellt genau einen Datensatz in
DXP SQZ Document Headerfür das Core‑Dokument (DXP Document). - Setzt Identifikationsfelder wie
Core Document No.und die SQUEEZE‑API Document ID. - Weist Header‑Felder aus JSON anhand der konfigurierten Zuordnungen zu:
DXP Field Mapping(Feldzuordnung)DXP Custom Field Mapping(Benutzerdefinierte Feldzuordnung)
- Respektiert
DXP Custom Field Mapping.Validate App Fieldund entscheidet damit, ob beim Zuweisen der OnValidate‑Trigger ausgeführt wird. - Führt das Integration‑Event
OnBeforeModifySQUEEZEDocumentHeader(...)als Extension‑Hook aus. - Für die eingebauten Standard‑SQUEEZE‑Klassen wird zusätzlich Standard‑Post‑Processing ausgeführt (z. B. alternative IBAN/USt‑ID‑Ermittlung, Lieferantenaktualisierung, Standard‑Buchungsdatum, Duplikatsprüfung).
- Erstellt genau einen Datensatz in
-
SqzDocumentMgt.CreateSQUEEZEDocLine(DocHeader, RawJson)- Erstellt die
DXP SQZ Document Line‑Datensätze basierend auf den JSON‑Rows. - Weist Line‑Felder nach dem gleichen Mapping‑Prinzip zu (Standard + Custom; optional mit Validierungstriggern).
- Befüllt
Core Document No.auf den Lines. - Für Standard‑SQUEEZE‑Klassen wird zusätzlich Standard‑Line‑Post‑Processing angewendet (z. B. Übertragung erkannter Werte).
- Persistiert line‑bezogene Hilfsdaten (z. B. Koordinaten/Metadaten, die UI und Matching‑Logik nutzen).
- Erstellt die
procedure CreateSource(Document: Record "DXP Document"): Boolean
var
DocClassSetup: Record "DXP Document Class Setup";
AutoValidationMgt: Codeunit "DXP Automatic Validation Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
DocMgt: Codeunit "DXP Document Mgt.";
SqzDocumentMgt: Codeunit "DXP SQZ Document Mgt.";
SqzApiMgt: Codeunit "DXP SQZ API Mgt.";
RawJson: JsonObject;
DocHeader: Record "DXP SQZ Document Header";
AutomaticValidation: Boolean;
begin
if (not Document."JSON Raw".HasValue()) or (Document.Status <> Document.Status::Imported) then
exit(false);
// 1) Unverarbeitetes JSON lesen
RawJson := JsonHelper.JObjectFromBlob(Document.RecordId(), Document.FieldNo("JSON Raw"));
// 2) SQUEEZE‑Source‑Dokument mit den generischen Hilfsfunktionen erstellen
// (Feldzuordnung + optionales Validierungs‑Trigger‑Verhalten wird im Helper behandelt)
SqzDocumentMgt.CreateSQUEEZEDocHeader(Document, DocHeader, RawJson);
SqzDocumentMgt.CreateSQUEEZEDocLine(DocHeader, RawJson);
// 3) Core → SQUEEZE‑Source‑Header verknüpfen
DocMgt.UpdateDocumentAfterTransfer(Document."No.", Document.Status::Transferred, DocHeader."API Document ID", DocHeader.RecordId());
// 4) Optional: Anhänge herunterladen und speichern
// (gesteuert über die Dokumentenklassen‑Einrichtung)
if DocClassSetup.Get(DocHeader."Document Class") then
if DocClassSetup."DXP Download Attachments" then
SqzApiMgt.DownloadAndSaveAttachments(DocHeader);
// 5) Optional: Automatische Validierung
// Wenn aktiviert, führt die Validierung die Plausibilitätsprüfungen aus und erstellt das „Processed JSON“.
AutomaticValidation := AutoValidationMgt.AutomaticValidationActivated(DocHeader."No.");
if AutomaticValidation then
SqzDocumentMgt.ValidateSQUEEZEDocument(DocHeader, AutomaticValidation);
exit(true);
end;
7) Schritt 5 — Validierung + Übergabe „Processed JSON“
7.1 Validierung: IsSourceDataPlausible
Nutzen Sie das Core‑Plausibility‑Framework, damit Fehler konsistent angezeigt werden:
procedure IsSourceDataPlausible(Source: Variant; var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary): Boolean
var
PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.";
Header: Record "DXP SQZ Document Header";
begin
if not Source.IsRecord then
exit(false);
Header := Source;
TempPlausibilityCheckEntry.DeleteAll();
PlausibilityCheck.FieldIsEmpty(Header, Header.FieldNo("Buy-from Vendor No."), 0, false, false);
PlausibilityCheck.CheckPostingDate(Header."Posting Date", Header.FieldNo("Posting Date"));
PlausibilityCheck.GetPlausibilityCheckEntries(TempPlausibilityCheckEntry);
exit(TempPlausibilityCheckEntry.IsEmpty());
end;
7.2 „Processed JSON“ bauen und an Core übergeben: CreateProcessedJsonFromSource
„Processed JSON“ wird von Core in DXP Document.JSON Processed gespeichert und an Ihre Zielverarbeitung übergeben.
procedure CreateProcessedJsonFromSource(Source: Variant)
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
DocMgt: Codeunit "DXP Document Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
Header: Record "DXP SQZ Document Header";
Line: Record "DXP SQZ Document Line";
HeaderJObj: JsonObject;
LinesJArr: JsonArray;
LineJObj: JsonObject;
begin
Header := Source;
HeaderJObj.Add(CoreTokenMgt.GetVendorNoTok(), Header."Buy-from Vendor No.");
HeaderJObj.Add(CoreTokenMgt.GetDocDateTok(), Header."Document Date");
HeaderJObj.Add(CoreTokenMgt.GetDocReferenceTok(), Header."Document Reference");
// Benutzerdefinierte Felder (Erweiterungsfelder) aus den Source‑Tabellen hinzufügen
HeaderJObj.Add(CoreTokenMgt.GetCustomFieldsTok(), JsonHelper.Rec2JsonFieldArray(Header, true, true, Header."Document Class", Enum::"DXP Field Type"::Header));
Line.SetRange("Document No.", Header."No.");
if Line.FindSet() then
repeat
Clear(LineJObj);
LineJObj.Add(CoreTokenMgt.GetDescriptionTok(), Line.Description);
LineJObj.Add(CoreTokenMgt.GetQtyTok(), Line.Quantity);
LineJObj.Add(CoreTokenMgt.GetCustomFieldsTok(), JsonHelper.Rec2JsonFieldArray(Line, true, true, Header."Document Class", Enum::"DXP Field Type"::Line));
LinesJArr.Add(LineJObj);
until Line.Next() = 0;
DocTransferMgt.AddDocLinesToHeaderJson(HeaderJObj, LinesJArr);
// An Core‑Zielverarbeitung übergeben
DocMgt.UpdateDocument(
Header."Core Document No.",
Enum::"DXP Document Status"::Transferred,
Enum::"DXP Target Document Process"::"MY Create Custom Document",
Enum::"DXP Next process step"::"Standard document",
HeaderJObj);
end;
8) Schritt 6 — Eigenes Ziel‑Dokument erstellen
Wenn Core Ihren eigenen Ziel‑Datensatz erstellen soll, erweitern Sie DXP Target Document Process und implementieren Sie DXP IDocument Processing:
enumextension 50102 "MY Target Doc Process Ext." extends "DXP Target Document Process"
{
value(50102; "MY Create Custom Document")
{
Caption = 'Create My Custom Document';
Implementation = "DXP IDocument Processing" = "MY Custom Doc Creation";
}
}
codeunit 50103 "MY Custom Doc Creation" implements "DXP IDocument Processing"
{
procedure ProcessStandardDocument(JObject: JsonObject): RecordId
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
MyDoc: Record "MY Custom Document";
TargetVariant: Variant;
begin
MyDoc.Init();
MyDoc.Validate("Vendor No.", JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetVendorNoTok(), false));
MyDoc.Validate("Document Date", JsonHelper.ValAsDate(JObject, CoreTokenMgt.GetDocDateTok(), false));
MyDoc.Insert(true);
// Überträgt Metadaten sowie benutzerdefinierte/zusätzliche Felder anhand der Core‑Zuordnungen in den Ziel‑Datensatz.
TargetVariant := MyDoc;
DocTransferMgt.ProcessAdditionalInformation(JObject, TargetVariant);
MyDoc := TargetVariant;
exit(MyDoc.RecordId());
end;
}
Hinweis: Die Übertragung von Metadaten sowie benutzerdefinierten/zusätzlichen Feldern ist im obigen Beispiel bereits enthalten und basiert auf den Core‑Zuordnungstabellen.
9) Fehlerbehebung (schnelle Prüfungen)
- Keine Einträge in
DXP SQZ Import Queue→ Dokumentenklassen‑Einrichtung für SQUEEZE ist unvollständig. - Core‑
DXP Documentexistiert, aber kein Source‑Datensatz → IhrCreateSource(Document)ist fehlgeschlagen oder gibtfalsezurück. - Source existiert, aber Ziel wird nicht erstellt →
CreateProcessedJsonFromSourcewird nicht aufgerufen oderDXP Target Document Processist nicht konfiguriert. - Falsches Trigger‑Verhalten beim Zuweisen →
DXP Custom Field Mapping.Validate App FieldundValidateprüfen.Validatesteuert, ob die Validierung des Ziel‑Feldes (OnValidate) ausgeführt wird.
10) Was Core automatisch macht
Wenn Sie DXP Document Mgt.UpdateDocument(...) aufrufen:
- Core speichert das „Processed JSON“ in
DXP Document.JSON Processed. - Core setzt
DXP Document.Statusauf den übergebenen Status. - Core verknüpft/aktualisiert
DXP Document.Linked-to Record Idmit dem Datensatz, den IhreDXP IDocument Processing‑Implementierung zurückgibt. - Core überträgt Core‑Attachments auf den zurückgegebenen Datensatz (und hängt typischerweise das „Processed JSON“ als
.json‑Attachment an).
Erstellung benutzerdefinierter Dokumente (Individuelle Verarbeitung)
Inhaltsverzeichnis
- Überblick
- Verstehen des Dokumentenablaufs
- JSON-Datenstruktur
- Schnellstart: Einfache benutzerdefinierte Verarbeitung
Überblick
Dieses Handbuch erklärt, wie Sie benutzerdefinierte Business Central-Dokumente aus JSON-Daten erstellen, die von DEXPRO Core bereitgestellt werden. Das System empfängt Dokumente mit dem Status "Custom Processing" (Individuelle Verarbeitung), die Drittanbieter-Entwickler in jeden BC-Dokumententyp umwandeln können (Bestellungen, Verkaufsaufträge, Fibu-Buchblätter, Serviceaufträge usw.).
Was Sie lernen werden
- Wie Sie Dokumente abfangen, die für die individuelle Verarbeitung markiert sind
- Die JSON-Struktur mit Dokumentenkopf, Zeilen, Metadaten und benutzerdefinierten Feldern
- Wie Sie Ihr benutzerdefiniertes Dokument erstellen
Verstehen des Dokumentenablaufs
Kernworkflow
┌─────────────────────────────────────────────────────────────────┐
│ 1. Dokumentenimport │
│ JSON-Rohdaten → DXP Document (Status: Imported) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 2. Erstellung des Quelldokuments │
│ ISourceDocument.CreateSource() → Ihre Quelltabellen │
│ (z.B. SQZ Document Header/Lines) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 3. Validierung & Plausibilitätsprüfungen │
│ ISourceDocument.IsSourceDataPlausible() │
│ → Validiert Datenqualität, prüft auf Fehler │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 4. Verarbeitetes JSON erstellen │
│ ISourceDocument.CreateProcessedJsonFromSource() │
│ → Erstellt JSON-Struktur für Zieldokument │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 5. Core-Dokument mit "Custom Processing" Status aktualisieren │
│ UpdateDocument() → Setzt Status auf "Custom Processing" │
│ → Speichert JSON Processed in DXP Document │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 6. Ihre benutzerdefinierte Verarbeitung (HIER SETZEN SIE AN!) │
│ Ereignisse abonnieren oder Interface implementieren │
│ → JSON Processed aus DXP Document lesen │
│ → Ihr BC-Zieldokument erstellen │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 7. Finale Statusaktualisierung │
│ Dokumentstatus → Transferred oder Finished │
│ Linked-to Record Id → Ihr erstelltes BC-Dokument │
└─────────────────────────────────────────────────────────────────┘
Wichtige Statuswerte
| Status | Beschreibung |
|---|---|
| Imported | JSON-Rohdaten empfangen, noch nicht verarbeitet |
| Transferred | Quelldokument erstellt, bereit zur Verarbeitung |
| Custom Processing | Ihr Zielstatus - Dokument bereit für benutzerdefinierte Verarbeitung |
| Closed | Zieldokument erfolgreich verbucht oder ggfs. bezahlt |
| Deleted | Verarbeitung abgebrochen, Dokument gelöscht |
JSON-Datenstruktur
Überblick
Das "JSON Processed" Blob in der DXP Document-Tabelle enthält ein strukturiertes JSON-Objekt mit allen Informationen, die zum Erstellen Ihres Zieldokuments benötigt werden.
JSON-Struktur (Auszug)
{
// ═══════════════════════════════════════════════════════════
// KOPFBEREICH - Dokumentenebene Informationen
// ═══════════════════════════════════════════════════════════
"Type": "Invoice", // Dokumenttyp: Invoice, Credit Memo, Order, usw.
"VendorNo": "VENDOR001", // Kreditoren-/Kundennummer
"DocumentDate": "2025-10-15", // Belegdatum
"PostingDate": "2025-10-16", // Buchungsdatum
"DocumentReference": "INV-2025-001", // Externe Belegnummer
"OrderNo": "PO-12345", // Referenz zur Bestellung (falls vorhanden)
"PostingDescription": "Invoice Q4", // Buchungsbeschreibung
"NetAmount": 1000.00, // Nettobetrag (ohne MwSt.)
"TotalAmount": 1190.00, // Bruttobetrag (inkl. MwSt.)
"TaxAmount": 190.00, // Gesamter Steuerbetrag
"Currency": "EUR", // Währungscode
// ───────────────────────────────────────────────────────────
// DIMENSIONEN - Kopfebene Dimensionen als Schlüssel-Wert-Paare
// ───────────────────────────────────────────────────────────
"Dimensions": {
"DEPARTMENT": "SALES",
"PROJECT": "PROJ001",
"COSTCENTER": "CC-100"
},
// ───────────────────────────────────────────────────────────
// BENUTZERDEFINIERTE FELDER - Zusätzliche Kopffelder (siehe unten)
// ───────────────────────────────────────────────────────────
"CustomFields": [
{
"Id": 50100,
"Name": "CustomerNo",
"Value": "CUST001",
"Caption": "Customer Number"
},
{
"Id": 50101,
"Name": "DeliveryTerms",
"Value": "EXW",
"Caption": "Delivery Terms"
}
],
// ───────────────────────────────────────────────────────────
// METADATEN - Systemgenerierte Feldzuordnungen
// ───────────────────────────────────────────────────────────
"Metadata": [
{
"DocumentClass": "DXP Invoice / Credit Memo",
"FieldType": "Header",
"FieldId": 101,
"Value": "Additional Info"
}
],
// ═══════════════════════════════════════════════════════════
// ZEILEN-BEREICH - Dokumentzeilen
// ═══════════════════════════════════════════════════════════
"Lines": [
{
// ─────────────────────────────────────────────────────────
// Zeilen-Grundinformationen
// ─────────────────────────────────────────────────────────
"Type": "Item", // Item, G/L Account, Charge (Item), Fixed Asset
"No": "ITEM001", // Artikel-/Kontonummer
"Description": "Product A", // Zeilenbeschreibung
"VendorItemNo": "VEND-SKU-123", // Kreditorenartikelnummer
"Quantity": 10.0, // Menge
"UnitOfMeasure": "PCS", // Einheitencode
"DirectUnitCost": 100.00, // EK-Preis
"LineDiscount": 5.0, // Zeilenrabatt in Prozent
// ─────────────────────────────────────────────────────────
// Zeilen-Beträge & Steuern
// ─────────────────────────────────────────────────────────
"NetAmount": 950.00, // Zeilennettobetrag
"TotalAmount": 1130.50, // Zeilenbruttobetrag
"TaxRate": 19.0, // Steuersatz in Prozent
"VATBusPostingGroup": "DOMESTIC",
"VATProdPostingGroup": "STANDARD",
"GenBusPostingGroup": "DOMESTIC",
"GenProdPostingGroup": "RETAIL",
// ─────────────────────────────────────────────────────────
// Bestellreferenz (für Zuordnung)
// ─────────────────────────────────────────────────────────
"OrderNo": "PO-12345", // Referenzierte Bestellnummer
"OrderLineNo": 10000, // Referenzierte Bestellzeilennummer
"ReceiptNo": "RCP-001", // Referenzierte Wareneingangsnummer
"ReceiptLineNo": 10000, // Referenzierte Wareneingangszeile
// ─────────────────────────────────────────────────────────
// Zeilen-Dimensionen
// ─────────────────────────────────────────────────────────
"Dimensions": {
"DEPARTMENT": "PROD",
"PROJECT": "PROJ001"
},
// ─────────────────────────────────────────────────────────
// Zeilen-Benutzerdefinierte Felder
// ─────────────────────────────────────────────────────────
"CustomFields": [
{
"Id": 50200,
"Name": "SerialNo",
"Value": "SN-12345",
"Caption": "Serial Number"
}
],
// ─────────────────────────────────────────────────────────
// Zeilen-Metadaten
// ─────────────────────────────────────────────────────────
"Metadata": [
{
"DocumentClass": "DXP Invoice / Credit Memo",
"FieldType": "Line",
"FieldId": 201,
"Value": "Line-specific metadata"
}
]
}
// ... weitere Zeilen
]
}
Benutzerdefinierte Felder vs. Metadaten
Benutzerdefinierte Felder (Custom Fields):
-
Benutzerdefinierte Felder aus Ihrer App
-
Ggfs. zugeordnet über Custom Field Mapping
-
Können jedem Feld in der Squeeze-Validierung zugeordnet werden
-
Beispiel: Hinzufügen einer "Kundennr." zur Squeeze-Validierung
Metadaten:
-
Systemgenerierte Felder
-
Vom Squeeze-System extrahiert, aber keinem Feld in BC zugeordnet
Schnellstart: Einfache benutzerdefinierte Verarbeitung
Szenario
Sie möchten einen benutzerdefinierten Dokumenttyp (z.B. einen Warenausgang) aus Dokumenten erstellen, die mit dem Status "Custom Processing" markiert sind.
Schritt 1: Integration Event abonnieren
Erstellen Sie eine Codeunit, um Dokumente mit dem Status "Custom Processing" abzufangen:
codeunit 50100 "My Custom Document Handler"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Mgt.",
'OnAfterWriteProcessedJsonToBlob', '', true, true)]
local procedure OnAfterWriteProcessedJsonToBlob(
var Document: Record "DXP Document";
var ProcessedJSONObj: JsonObject)
begin
// Nur Custom Processing Status behandeln
if Document.Status <> Document.Status::"Custom Processing" then
exit;
// Ihr benutzerdefiniertes Dokument erstellen
CreateMyCustomDocument(Document, ProcessedJSONObj);
end;
local procedure CreateMyCustomDocument(
var Document: Record "DXP Document";
ProcessedJSON: JsonObject)
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
MyCustomHeader: Record "My Custom Document Header";
MyCustomLine: Record "My Custom Document Line";
LineJArray: JsonArray;
LineJToken: JsonToken;
LineJObj: JsonObject;
begin
// ═══════════════════════════════════════════════════════
// 1. KOPF ERSTELLEN
// ═══════════════════════════════════════════════════════
MyCustomHeader.Init();
MyCustomHeader."No." := ''; // Wird durch Nummernserie zugewiesen
// Standard-Kopffelder lesen
MyCustomHeader."Vendor No." :=
JsonHelper.ValAsTxt(ProcessedJSON, CoreTokenMgt.GetVendorNoTok(), false);
MyCustomHeader."Document Date" :=
JsonHelper.ValAsDate(ProcessedJSON, CoreTokenMgt.GetDocDateTok(), false);
MyCustomHeader."Document Reference" :=
JsonHelper.ValAsTxt(ProcessedJSON, CoreTokenMgt.GetDocReferenceTok(), false);
MyCustomHeader.Insert(true);
// ═══════════════════════════════════════════════════════
// 2. DIMENSIONEN VERARBEITEN (wenn Ihr Dokument diese unterstützt)
// ═══════════════════════════════════════════════════════
ProcessHeaderDimensions(ProcessedJSON, MyCustomHeader);
// ═══════════════════════════════════════════════════════
// 3. BENUTZERDEFINIERTE FELDER VERARBEITEN
// ═══════════════════════════════════════════════════════
ProcessCustomFields(ProcessedJSON, MyCustomHeader);
// ═══════════════════════════════════════════════════════
// 4. ZEILEN ERSTELLEN
// ═══════════════════════════════════════════════════════
LineJArray := JsonHelper.ReadJArrayFromObj(ProcessedJSON, CoreTokenMgt.GetLinesTok());
foreach LineJToken in LineJArray do begin
LineJObj := LineJToken.AsObject();
MyCustomLine.Init();
MyCustomLine."Document No." := MyCustomHeader."No.";
MyCustomLine."Line No." := GetNextLineNo(MyCustomHeader."No.");
// Zeilenfelder lesen
MyCustomLine."Item No." :=
JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetNoTok(), false);
MyCustomLine.Description :=
JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetDescriptionTok(), false);
MyCustomLine.Quantity :=
JsonHelper.ValAsDec(LineJObj, CoreTokenMgt.GetQtyTok(), false);
MyCustomLine."Unit of Measure" :=
JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetUoMTok(), false);
MyCustomLine.Insert(true);
// Zeilen-Dimensionen und benutzerdefinierte Felder verarbeiten, falls erforderlich
ProcessLineDimensions(LineJObj, MyCustomLine);
ProcessLineCustomFields(LineJObj, MyCustomLine);
end;
// ═══════════════════════════════════════════════════════
// 5. CORE-DOKUMENTSTATUS AKTUALISIEREN
// ═══════════════════════════════════════════════════════
UpdateCoreDocument(Document, MyCustomHeader);
end;
local procedure ProcessHeaderDimensions(ProcessedJSON: JsonObject; var MyCustomHeader: Record "My Custom Document Header")
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
DimensionsJObj: JsonObject;
DimSetID: Integer;
begin
// Dimensionen aus JSON lesen
if ProcessedJSON.Contains(CoreTokenMgt.GetDimensionsTok()) then begin
ProcessedJSON.Get(CoreTokenMgt.GetDimensionsTok(), DimensionsJObj);
// In Dimensionssatz-ID konvertieren
if DocTransferMgt.GetDimSetIdFromJsonObj(DimensionsJObj, DimSetID) then begin
MyCustomHeader."Dimension Set ID" := DimSetID;
MyCustomHeader.Modify(true);
end;
end;
end;
local procedure ProcessCustomFields(ProcessedJSON: JsonObject; var MyCustomHeader: Record "My Custom Document Header")
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
CustomFieldsJArray: JsonArray;
CustomFieldJToken: JsonToken;
CustomFieldJObj: JsonObject;
FieldName: Text;
FieldValue: Text;
begin
// Benutzerdefinierte Felder-Array lesen
if not ProcessedJSON.Contains(CoreTokenMgt.GetCustomFieldsTok()) then
exit;
CustomFieldsJArray := JsonHelper.ReadJArrayFromObj(ProcessedJSON, CoreTokenMgt.GetCustomFieldsTok());
foreach CustomFieldJToken in CustomFieldsJArray do begin
CustomFieldJObj := CustomFieldJToken.AsObject();
FieldName := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetNameTok(), false);
FieldValue := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetValueTok(), false);
// Zu Ihren benutzerdefinierten Feldern zuordnen
case FieldName of
'CustomerNo':
MyCustomHeader."Customer No." := CopyStr(FieldValue, 1, 20);
'DeliveryTerms':
MyCustomHeader."Delivery Terms" := CopyStr(FieldValue, 1, 10);
// Weitere Feldzuordnungen nach Bedarf hinzufügen
end;
end;
MyCustomHeader.Modify(true);
end;
local procedure ProcessLineDimensions(LineJObj: JsonObject; var MyCustomLine: Record "My Custom Document Line")
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
DimensionsJObj: JsonObject;
DimSetID: Integer;
begin
if LineJObj.Contains(CoreTokenMgt.GetDimensionsTok()) then begin
LineJObj.Get(CoreTokenMgt.GetDimensionsTok(), DimensionsJObj);
if DocTransferMgt.GetDimSetIdFromJsonObj(DimensionsJObj, DimSetID) then begin
MyCustomLine."Dimension Set ID" := DimSetID;
MyCustomLine.Modify(true);
end;
end;
end;
local procedure ProcessLineCustomFields(LineJObj: JsonObject; var MyCustomLine: Record "My Custom Document Line")
var
CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
JsonHelper: Codeunit "DXP Json Helper";
CustomFieldsJArray: JsonArray;
CustomFieldJToken: JsonToken;
CustomFieldJObj: JsonObject;
FieldName: Text;
FieldValue: Text;
begin
if not LineJObj.Contains(CoreTokenMgt.GetCustomFieldsTok()) then
exit;
CustomFieldsJArray := JsonHelper.ReadJArrayFromObj(LineJObj, CoreTokenMgt.GetCustomFieldsTok());
foreach CustomFieldJToken in CustomFieldsJArray do begin
CustomFieldJObj := CustomFieldJToken.AsObject();
FieldName := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetNameTok(), false);
FieldValue := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetValueTok(), false);
// Zu Ihren benutzerdefinierten Zeilenfeldern zuordnen
case FieldName of
'SerialNo':
MyCustomLine."Serial No." := CopyStr(FieldValue, 1, 50);
// Weitere Feldzuordnungen hinzufügen
end;
end;
MyCustomLine.Modify(true);
end;
local procedure UpdateCoreDocument(var Document: Record "DXP Document"; MyCustomHeader: Record "My Custom Document Header")
var
DocumentMgt: Codeunit "DXP Document Mgt.";
begin
// Core-Dokument aktualisieren, um es mit Ihrem erstellten Dokument zu verknüpfen
Document.Status := Document.Status::Transferred;
Document."Linked-to Record Id" := MyCustomHeader.RecordId;
Document.Modify(true);
// Optional: Anhänge von Core zu Ihrem Dokument übertragen
TransferAttachments(Document, MyCustomHeader);
end;
local procedure TransferAttachments(Document: Record "DXP Document"; MyCustomHeader: Record "My Custom Document Header")
var
DocAttachment: Record "DXP Document Attachment";
MyDocAttachment: Record "Document Attachment";
InStr: InStream;
begin
DocAttachment.SetRange("Document No.", Document."No.");
if DocAttachment.FindSet() then
repeat
MyDocAttachment.Init();
MyDocAttachment.ID := 0;
DocAttachment."File Content".CreateInStream(InStr);
MyDocAttachment.SaveAttachmentFromStream(
InStr,
MyCustomHeader.RecordId,
DocAttachment."File Name");
until DocAttachment.Next() = 0;
end;
local procedure GetNextLineNo(DocumentNo: Code[20]): Integer
var
MyCustomLine: Record "My Custom Document Line";
begin
MyCustomLine.SetRange("Document No.", DocumentNo);
if MyCustomLine.FindLast() then
exit(MyCustomLine."Line No." + 10000);
exit(10000);
end;
}
Wichtige Hilfs-Codeunits
| Codeunit | Zweck |
|---|---|
| DXP Core Token Mgt. | Stellt Token-Namen für JSON-Felder bereit (GetVendorNoTok(), GetDocDateTok(), usw.) |
| DXP Json Helper | JSON-Parsing-Hilfsfunktionen (ValAsTxt(), ValAsDate(), ReadJArrayFromObj(), usw.) |
| DXP Document Transfer Mgt. | Dimensionsverarbeitung, Metadatenübertragung, Behandlung benutzerdefinierter Felder |
| DXP Document Mgt. | Kern-Dokumentenverwaltung (UpdateDocument(), UpdateDocumentStatus(), usw.) |
Bei Fragen oder Unklarheiten wenden Sie sich bitte an die DEXPRO Solutions GmbH.
Einbetten des SQUEEZE Viewer‑Parts in eigene Pages
Diese Anleitung beschreibt, wie Sie den SQUEEZE Viewer in beliebige Seiten einbetten (eigene Pages oder Page Extensions) – über den wiederverwendbaren Viewer‑Part:
- Page: "DXP SQZ Viewer Part" (PageType =
CardPart) - Source table: "DXP SQZ Document Header"
Der Viewer‑Part hostet die SQUEEZE Control Add-ins und lädt die Preview‑URL anhand des aktuellen Datensatzes DXP SQZ Document Header.
Referenz‑Implementierung, die in dieser App bereits enthalten ist:
- Page "DXP SQZ Document (Generic)" (Card, SourceTable DXP SQZ Document Header) bettet den Viewer‑Part als FactBox ein und verdrahtet das Resident‑Sharing zur generischen Lines‑Subform.
- Page "DXP SQZ Doc. Generic Subform" (ListPart, SourceTable DXP SQZ Document Line) enthält eine bekannte, funktionierende Minimal‑Implementierung von
MarkRow().
Die Pages können Sie benutzen und mit ihren Feldern erweitern. Die Page "DXP SQZ Document (Generic)" verfügt über einen Viewer in der Factbox und die wichtigsten Actions.
1) Voraussetzungen
-
Ihre Extension muss von der DEXPRO SQUEEZE App abhängig sein (damit Page/Control Add-ins als Symbole verfügbar sind).
-
Der Host‑Datensatz muss eine Möglichkeit bieten, einen DXP SQZ Document Header Datensatz zu referenzieren.
- Die
SourceTabledes Viewer‑Parts ist fest auf DXP SQZ Document Header. - Deshalb muss Ihre Seite ein Feld haben (oder bereitstellen), das sich in
SubPageLinkverwenden lässt, um den Header zu finden. Alternativ kann der Record in dem Viewer-Part gesetzt werden - Beispiele folgen weiter unten.
- Die
-
SQUEEZE muss aktiviert und konfiguriert sein (Setup + API Key). Der Viewer‑Part lädt absichtlich nicht, wenn das Modul nicht aktiviert ist.
2) Empfohlenes Einbettungsmuster
2.1 Als FactBox einbetten (empfohlen)
Für die meisten Szenarien (Card Pages, List Pages) platzieren Sie den Viewer in area(FactBoxes).
Wenn die SourceTable Ihrer Seite DXP SQZ Document Header ist
layout
{
area(FactBoxes)
{
part(SQZViewer; "DXP SQZ Viewer Part")
{
ApplicationArea = All;
Caption = 'Viewer';
// Link the FactBox part to the current SQZ header
SubPageLink = "No." = field("No.");
}
}
}
Wenn die SourceTable Ihrer Seite NICHT DXP SQZ Document Header ist
Sie können den Viewer‑Part trotzdem einbetten, sofern Ihr Datensatz ein Feld enthält, das die SQUEEZE Header‑Nummer speichert.
Beispiel: Ihr Datensatz hat ein Feld "SQZ Document No." : Code[20]
layout
{
area(FactBoxes)
{
part(SQZViewer; "DXP SQZ Viewer Part")
{
ApplicationArea = All;
Caption = 'Viewer';
// Link the viewer part’s "No." to your field
SubPageLink = "No." = field("SQZ Document No.");
}
}
}
Wichtig:
- Setze am Part nicht
Enabled = false. Wenn eine FactBox‑Part deaktiviert ist, kann das verhindern, dass das Control Add-in „ready“ wird – dadurch bleibt der Viewer ggf. dauerhaft leer.
2.2 Viewer dynamisch binden (ohne SubPageLink)
Wenn Ihre Host‑Seite keinen einfachen SubPageLink anbieten kann (z. B. weil es sich um eine Zielbeleg‑Seite wie Purchase Invoice handelt und dort die SQUEEZE Belegnummer nicht gespeichert ist), können Sie den Viewer‑Part trotzdem einbetten und im Code binden.
Konzept:
- Viewer‑Part als FactBox hinzufügen – ohne
SubPageLink. - In
OnAfterGetCurrRecord()den relevantenRecord "DXP SQZ Document Header"auflösen. - Den Datensatz per
CurrPage.<PartName>.Page.SetSqzRecord(SqzHeader);in den Part pushen.
Warum SetSqzRecord?
- Im DEXPRO SQUEEZE Viewer‑Part läuft das Laden der URL in
OnAfterGetCurrRecord(). - Beim Navigieren innerhalb einer Seite (z. B. Wechsel zwischen Purchase Invoices) kann
SetRecord(...)allein dazu führen, dass die FactBox nicht sofort neu lädt. SetSqzRecord(...)ist dafür gedacht, den Header sauber neu zu binden und einen Refresh auszulösen, sodass die korrekte Preview ohne Schließen/Öffnen der Seite geladen wird.
Beispiel‑Gerüst:
layout
{
area(FactBoxes)
{
part(SQZViewer; "DXP SQZ Viewer Part")
{
ApplicationArea = All;
Caption = 'Viewer';
}
}
}
trigger OnAfterGetCurrRecord()
var
SqzHeader: Record "DXP SQZ Document Header";
begin
if TryResolveSqzHeaderForCurrentRecord(SqzHeader) then
CurrPage.SQZViewer.Page.SetSqzRecord(SqzHeader);
end;
Dieses Pattern ist besonders für Third‑party Pages hilfreich, weil es vermeidet, „SQUEEZE Document No.“ als Tabellenfeld persistieren zu müssen.
3) Viewer‑Modus (Belegübersicht / Positionsfokus / Abgedockt)
Wenn der Viewer als FactBox eingebettet ist, sind Felder typischerweise nicht editierbar. Deshalb bietet der Viewer‑Part Actions, um den Viewer‑Modus zu ändern.
Was beim Wechsel des Modus passiert:
- Belegübersicht: Zeigt eine Übersichtliche Darstellung des Viewers an.
- Positionsfokus: Zeigt eine schmalere Darstellung des Viewers an.
- Abgedockt: Öffnet den Viewer in einem externen Fenster
Für Third‑party Entwickler:
- Sie müssen keine eigene Mode‑Logik implementieren.
- Nutzen Sie die Actions des Viewer‑Parts (erscheinen im FactBox Action‑Menü).
4) Optional, aber wichtig: Zeilen‑Highlighting aktivieren (MarkRow)
Wenn Sie eine Lines‑Subform haben und die Benutzererfahrung „Zeile klicken → Viewer markiert Koordinaten“ wünschen, muss Ihre Lines‑Page Messages über dieselbe Viewer‑Resident‑Instanz posten, die der Viewer‑Part initialisiert.
Warum das wichtig ist:
- Die Viewer‑UI ist eine Control Add‑in Instanz, die in einer Codeunit
DXP SQUEEZE Viewer Residentgespeichert wird. - Wenn Ihre Lines‑Page eine eigene Variable
DXP SQUEEZE Viewer Residentverwendet (die nicht vom Viewer‑Part initialisiert wurde), hatApiMgt.PostMessage(...)keine Control‑Add‑in Instanz zum Ansprechen – es wird nichts markiert.
4.1 Pattern (Host‑Page verdrahtet Viewer‑Resident in Lines)
Annahmen:
- Ihre Header‑Page hat:
part(SQZViewer; "DXP SQZ Viewer Part")part(DocumentLines; <Ihre Lines ListPart>)
- Ihre Lines‑ListPart stellt eine Procedure bereit:
SetViewerResident(var NewResident: Codeunit "DXP SQUEEZE Viewer Resident")
Das ist ein expliziter Vertrag/Annahme für interaktives Line‑Highlighting.
Ergänzen Sie das auf Ihrer Header‑Page:
trigger OnAfterGetCurrRecord()
var
SharedResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
CurrPage.SQZViewer.Page.GetViewerResident(SharedResident);
CurrPage.DocumentLines.Page.SetViewerResident(SharedResident);
end;
Hinweise:
- Das gehört in
OnAfterGetCurrRecord()der Host‑Page (dort ist der aktuelle Header stabil, und die Parts existieren). - Wenn Ihre Host‑Page andere Part‑Namen verwendet, passen Sie
CurrPage.<PartName>.Page...entsprechend an.
4.2 Was die Lines‑Subform tun muss
Ihre Lines‑Page sollte MarkRow() in OnAfterGetCurrRecord() aufrufen und MarkRow() ähnlich zur Standard‑Seite implementieren:
- Wenn der externe Viewer aktiv ist (Abgedockt), nur die State‑Tabelle aktualisieren.
- Ansonsten
ApiMgt.PostMessage(ApiMgt.MarkFieldByCoordinatesObj(Rec.RecordId), Resident)aufrufen.
Das ist die Mindestanforderung für interaktives Highlighting.
4.3 Referenz‑Implementierung: minimale Lines‑Subform mit MarkRow
Das ist ein bekannt funktionierendes Minimal‑Pattern (basierend auf der Standard SQUEEZE Lines‑Subform). Third‑party Entwickler können es kopieren und Felder/Repeater‑Spalten nach Bedarf anpassen:
page 70954672 "DXP SQZ Doc. Generic Subform"
{
Caption = 'Lines';
PageType = ListPart;
AutoSplitKey = true;
DelayedInsert = true;
SourceTable = "DXP SQZ Document Line";
RefreshOnActivate = true;
layout
{
area(content)
{
repeater(General)
{
field("Line No."; Rec."Line No.")
{
ApplicationArea = All;
Visible = false;
}
// Add your visible SQZ fields here...
}
}
}
trigger OnAfterGetCurrRecord()
begin
MarkRow();
end;
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
Resident: Codeunit "DXP SQUEEZE Viewer Resident";
MarkedLineNo: Integer;
procedure SetViewerResident(var NewResident: Codeunit "DXP SQUEEZE Viewer Resident")
begin
Resident := NewResident;
MarkedLineNo := 0;
end;
local procedure MarkRow()
var
DocHeader: Record "DXP SQZ Document Header";
LineCoordMgt: Codeunit "DXP SQZ Coordinates Mgt.";
ViewerState: Codeunit "DXP Viewer State";
begin
if MarkedLineNo = Rec."Line No." then
exit;
if not LineCoordMgt.CoordinateExists(Rec.RecordId) then
exit;
// Detached viewer: update the state table only
if IsExternalViewerActive() then begin
if DocHeader.Get(Rec."Document No.") then
ViewerState.UpdateViewerStateWithCoordinates(DocHeader."API Document ID", Rec.RecordId);
end else
// Internal viewer: post message to the control add-in instance via the shared resident
ApiMgt.PostMessage(ApiMgt.MarkFieldByCoordinatesObj(Rec.RecordId), Resident);
MarkedLineNo := Rec."Line No.";
end;
local procedure IsExternalViewerActive(): Boolean
var
ViewerState: Codeunit "DXP Viewer State";
begin
exit(ViewerState.GetViewerMode() = "DXP SQZ Viewer Mode"::Detached);
end;
}
5) Fehlersuche (Viewer bleibt leer)
5.1 Der Viewer lädt nie eine Preview
Prüfe zuerst:
- Ist das SQUEEZE Modul aktiviert und das Setup vollständig?
- Hat der verknüpfte DXP SQZ Document Header Datensatz eine gültige
"API Document ID"? - Ist der Viewer‑Modus aktuell Abgedockt und ein externer Viewer offen?
- Der interne Viewer lädt nicht, solange der externe Viewer geöffnet ist.
5.2 FactBox ist sichtbar, aber Control Add-in initialisiert nicht
- Deaktiviere den Viewer‑FactBox‑Part nicht über
Enabled = false. - Stelle sicher, dass die FactBox tatsächlich angezeigt wird (FactBoxes können vom Benutzer eingeklappt/ausgeblendet werden).
5.3 MarkRow hebt nichts hervor
- Stelle sicher, dass die Lines‑Page dieselbe Viewer‑Resident‑Instanz wie der Viewer‑Part nutzt (siehe Abschnitt 4).
- Stelle sicher, dass Koordinaten für den Zeilen‑Datensatz existieren (
DXP SQZ Coordinates Mgt.muss Koordinaten zuRec.RecordIdfinden).
6) Minimales Beispiel: Viewer in eine eigene Page Extension einbauen
pageextension 50100 "MY SQZ Doc Ext." extends "DXP SQZ Document (Generic)"
{
layout
{
addfirst(FactBoxes)
{
part(MySQZViewer; "DXP SQZ Viewer Part")
{
ApplicationArea = All;
Caption = 'Viewer';
SubPageLink = "No." = field("No.");
}
}
}
}
7) Hinweise / Einschränkungen
- Der Viewer‑State ist session‑getrieben (via
DXP Viewer State). Wenn mehrere Seiten mit Viewer gleichzeitig offen sind, können Modus/External‑Viewer‑State alle beeinflussen. - Der Viewer‑Part ist für Datensätze mit SQUEEZE‑Bezug gedacht; er versucht nicht, automatisch „irgendeinen“ Header zu suchen.
8) Beispiel: Viewer auf einem Zielbeleg anzeigen (Purchase Invoice)
Dieser Abschnitt adressiert ein häufiges Third‑party Szenario:
Annahmen:
- Der Zielbeleg (z. B. Purchase Invoice) wurde aus einem Core‑Beleg erstellt.
- Der Core‑Beleg ist weiterhin in der Tabelle "DXP Document" verfügbar.
- Der Core‑Beleg speichert eine Rückverknüpfung zum Ziel‑Datensatz im Feld "Linked-to Record Id".
- Der SQUEEZE Quell‑Header existiert noch und kann aus dem Core‑Beleg aufgelöst werden (typischerweise über Core Document No.).
8.1 Core‑Beleg aus dem Ziel‑Datensatz auflösen
local procedure TryGetCoreDocumentForTarget(TargetRecId: RecordId; var CoreDoc: Record "DXP Document"): Boolean
begin
CoreDoc.Reset();
CoreDoc.SetRange("Linked-to Record Id", TargetRecId);
exit(CoreDoc.FindFirst());
end;
8.2 SQUEEZE Header aus dem Core‑Beleg auflösen
local procedure TryGetSqzHeaderForCore(CoreDocNo: Code[20]; var SqzHeader: Record "DXP SQZ Document Header"): Boolean
begin
SqzHeader.Reset();
SqzHeader.SetRange("Core Document No.", CoreDocNo);
exit(SqzHeader.FindFirst());
end;
8.3 Viewer einbetten (dynamisches Binden)
Beispiel: Purchase Invoice erweitern (konzeptionell; Basis‑Page‑Name ggf. an Ihre Umgebung anpassen).
Diese Implementierung verwendet:
- Einen FactBox‑Part
- Ein
ShowViewer‑Flag, um den Part auszublenden, wenn kein SQZ Header aufgelöst werden kann. SetSqzRecord(...), damit die Preview beim Wechsel des Belegs sofort korrekt neu lädt.- Ein
SingleInstanceContext‑Codeunit, um Viewer‑Resident und SQZ‑Kontext mit der Purch. Invoice Subform zu teilen (FactBoxes und Subforms sind separate Pages).
pageextension 50100 "MY Purch. Invoice Viewer" extends "Purchase Invoice"
{
layout
{
addfirst(FactBoxes)
{
part(DXPSQZViewer; "DXP SQZ Viewer Part")
{
ApplicationArea = All;
Caption = 'SQUEEZE Viewer';
Visible = ShowViewer;
}
}
}
var
ShowViewer: Boolean;
trigger OnAfterGetCurrRecord()
var
CoreDoc: Record "DXP Document";
SqzHeader: Record "DXP SQZ Document Header";
SharedResident: Codeunit "DXP SQUEEZE Viewer Resident";
ViewerCtx: Codeunit "DXP SQZ Purch. Inv. Viewer Ctx";
begin
ShowViewer := false;
if not TryGetCoreDocumentForTarget(Rec.RecordId, CoreDoc) then
exit;
if not TryGetSqzHeaderForCore(CoreDoc."No.", SqzHeader) then
exit;
ShowViewer := true;
CurrPage.DXPSQZViewer.Page.SetSqzRecord(SqzHeader);
CurrPage.DXPSQZViewer.Page.GetViewerResident(SharedResident);
ViewerCtx.SetResident(SharedResident);
ViewerCtx.SetSqzContextForPurchInv(Rec."No.", SqzHeader."No.", SqzHeader."API Document ID");
end;
local procedure TryGetCoreDocumentForTarget(TargetRecId: RecordId; var CoreDoc: Record "DXP Document"): Boolean
begin
CoreDoc.Reset();
CoreDoc.SetRange("Linked-to Record Id", TargetRecId);
exit(CoreDoc.FindFirst());
end;
local procedure TryGetSqzHeaderForCore(CoreDocNo: Code[20]; var SqzHeader: Record "DXP SQZ Document Header"): Boolean
begin
SqzHeader.Reset();
SqzHeader.SetRange("Core Document No.", CoreDocNo);
exit(SqzHeader.FindFirst());
end;
}
Zugehöriges Context‑Codeunit (speichert Resident + SQZ‑Kontext, damit die Subform korrekt highlighten kann):
codeunit 50101 "MY SQZ Purch. Inv. Viewer Ctx"
{
SingleInstance = true;
procedure SetResident(var NewResident: Codeunit "DXP SQUEEZE Viewer Resident")
begin
Resident := NewResident;
HasResident := true;
end;
procedure TryGetResident(var OutResident: Codeunit "DXP SQUEEZE Viewer Resident"): Boolean
begin
if not HasResident then
exit(false);
OutResident := Resident;
exit(true);
end;
procedure SetSqzContextForPurchInv(PurchInvNo: Code[20]; SqzDocNo: Code[20]; ApiDocumentId: Text[50])
begin
PurchInvToSqzDocNo.Set(PurchInvNo, SqzDocNo);
PurchInvToApiDocumentId.Set(PurchInvNo, ApiDocumentId);
end;
procedure TryGetSqzContextForPurchInv(PurchInvNo: Code[20]; var SqzDocNo: Code[20]; var ApiDocumentId: Text[50]): Boolean
begin
if not PurchInvToSqzDocNo.Get(PurchInvNo, SqzDocNo) then
exit(false);
PurchInvToApiDocumentId.Get(PurchInvNo, ApiDocumentId);
exit(true);
end;
var
Resident: Codeunit "DXP SQUEEZE Viewer Resident";
HasResident: Boolean;
PurchInvToSqzDocNo: Dictionary of [Code[20], Code[20]];
PurchInvToApiDocumentId: Dictionary of [Code[20], Text[50]];
}
8.4 Wichtiger Hinweis: SQUEEZE Header‑Status nach Verarbeitung
Sie haben ein häufiges Setup beschrieben, in dem der SQUEEZE Header nach dem Erstellen des Zielbelegs noch existiert, aber Status = Deleted ist.
Der Viewer‑Part kann die Preview trotzdem laden, solange "API Document ID" vorhanden ist und SQUEEZE aktiviert ist.
Optionen:
- Wenn Sie die Preview nach Zielbeleg‑Erstellung nicht anzeigen möchten, bauen Sie eine Guard‑Logik auf der Host‑Page ein (Viewer‑Part dann nicht binden, wenn der SQZ Header „Deleted“ ist).
Welche Option korrekt ist, hängt von Ihren Prozessanforderungen ab.
9) Sonderfall: Hervorheben aus der Purchase Invoice Subform (Purchase Line → SQZ line)
Manchmal mächten Sie diese Benutzererfahrung auf einer Zielbeleg‑Seite:
In dieser Situation basiert Ihre Lines‑Page nicht auf "DXP SQZ Document Line", daher können Sie MarkFieldByCoordinatesObj(Rec.RecordId) nicht direkt aufrufen.
Stattdessen müssen Sie die passende SQUEEZE Line auflösen und danach mit der RecordId dieser SQUEEZE Line highlighten.
9.1 Zwei mögliche Verknüpfungsstrategien
Es gibt zwei realistische Wege, eine Einkaufszeile wieder auf eine SQUEEZE Line zu mappen:
-
Expliziter Allocation‑Link (nur in manchen Szenarien verfügbar)
- Verwendet Felder auf
"DXP SQZ Document Line":"Allocated Document Type"(enum"DXP Order Match Document Type")"Allocated Document No.""Allocated Document Line No."
- Verwendet Felder auf
-
Heuristischer Match nach Inhalt (empfohlen als Fallback)
- Verwendet Felder, die typischerweise auf beiden Seiten existieren (Type/No/Quantity/Unit Cost/Line Amount/Description).
- Das funktioniert auch dann, wenn keine Allocation‑Beziehung gepflegt wird.
- Es ist nicht mathematisch perfekt (Duplikate sind möglich), daher sollten Matching‑Regeln auf Ihren Use Case angepasst werden.
9.2 Empfohlenes Wiring (Host‑Page übergibt SQZ‑Kontext + Resident)
Sie benötigen in der Purchase‑Lines‑Subpage zwei Dinge:
- Den Viewer‑Resident (damit
PostMessage(...)die richtige Control‑Add‑in Instanz trifft) - Den aktuellen SQZ Header‑Kontext (damit Sie SQZ Lines auf das richtige Dokument filtern)
Empfohlenes Pattern auf der Host‑Page (nachdem Sie SqzHeader aufgelöst haben):
trigger OnAfterGetCurrRecord()
var
SharedResident: Codeunit "DXP SQUEEZE Viewer Resident";
SqzHeader: Record "DXP SQZ Document Header";
begin
if not TryResolveSqzHeaderForCurrentRecord(SqzHeader) then
exit;
CurrPage.DXPSQZViewer.Page.SetSqzRecord(SqzHeader);
CurrPage.DXPSQZViewer.Page.GetViewerResident(SharedResident);
ViewerCtx.SetResident(SharedResident);
ViewerCtx.SetSqzContextForPurchInv(Rec."No.", SqzHeader."No.", SqzHeader."API Document ID");
end;
9.3 Minimales Beispiel: Purch. Invoice Subform triggert Highlighting im Viewer
Dieses Beispiel erweitert Purch. Invoice Subform. Beachten Sie: der Datensatz der Basis‑Subform ist ein Record "Purchase Line", daher müssen die Resolver‑Prozeduren Record "Purchase Line" akzeptieren.
Das hier gezeigte Allocation‑Mapping ist die funktionierende Implementierung für Purchase‑Invoice‑Szenarien: es verknüpft über Receipt ("Receipt No." / "Receipt Line No.") statt über Belegnummer/Zeilennummer der Rechnung.
pageextension 50101 "MY Purch. Inv. Sf Mark" extends "Purch. Invoice Subform"
{
trigger OnAfterGetCurrRecord()
begin
MarkSqzLineForPurchInvLine();
end;
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
Resident: Codeunit "DXP SQUEEZE Viewer Resident";
ViewerState: Codeunit "DXP Viewer State";
LineCoordMgt: Codeunit "DXP SQZ Coordinates Mgt.";
ViewerCtx: Codeunit "DXP SQZ Purch. Inv. Viewer Ctx";
SqzDocNo: Code[20];
ApiDocumentId: Text[50];
local procedure MarkSqzLineForPurchInvLine()
var
SqzLine: Record "DXP SQZ Document Line";
begin
if not ViewerCtx.TryGetSqzContextForPurchInv(Rec."Document No.", SqzDocNo, ApiDocumentId) then
exit;
if not ViewerCtx.TryGetResident(Resident) then
exit;
if not TryResolveSqzLineForPurchLine(SqzDocNo, Rec, SqzLine) then
exit;
if not LineCoordMgt.CoordinateExists(SqzLine.RecordId) then
exit;
if ViewerState.GetViewerMode() = "DXP SQZ Viewer Mode"::Detached then
ViewerState.UpdateViewerStateWithCoordinates(ApiDocumentId, SqzLine.RecordId)
else
ApiMgt.PostMessage(ApiMgt.MarkFieldByCoordinatesObj(SqzLine.RecordId), Resident);
end;
local procedure TryResolveSqzLineForPurchLine(SqzDocNo: Code[20]; PurchLine: Record "Purchase Line"; var SqzLine: Record "DXP SQZ Document Line"): Boolean
begin
// 1) Allocation link via receipt (Purchase Invoice Szenario)
SqzLine.Reset();
SqzLine.SetRange("Document No.", SqzDocNo);
SqzLine.SetFilter("Allocated Document No.", '%1&<>%2', PurchLine."Receipt No.", '');
SqzLine.SetFilter("Allocated Document Line No.", '%1&<>%2', PurchLine."Receipt Line No.", 0);
if SqzLine.FindFirst() then
exit(true);
// 2) Fallback: content-based match (Type/No/Amounts)
exit(TryResolveSqzLineByContent(SqzDocNo, PurchLine, SqzLine));
end;
local procedure TryResolveSqzLineByContent(SqzDocNo: Code[20]; PurchLine: Record "Purchase Line"; var BestSqzLine: Record "DXP SQZ Document Line"): Boolean
var
Candidate: Record "DXP SQZ Document Line";
BestScore: Integer;
Score: Integer;
QtyTol: Decimal;
AmtTol: Decimal;
begin
QtyTol := 0.00001;
AmtTol := 0.01;
BestScore := 0;
Candidate.Reset();
Candidate.SetRange("Document No.", SqzDocNo);
// Prefer narrowing early on stable fields
Candidate.SetRange(Type, PurchLine.Type);
if PurchLine."No." <> '' then
Candidate.SetRange("No.", PurchLine."No.");
if not Candidate.FindSet() then
exit(false);
repeat
Score := 0;
// Strong signals
if Candidate.Type = PurchLine.Type then
Score += 20;
if (PurchLine."No." <> '') and (Candidate."No." = PurchLine."No.") then
Score += 40;
// Weak/medium signals (tolerant)
if (Candidate.Quantity <> 0) and (Abs(Candidate.Quantity - PurchLine.Quantity) <= QtyTol) then
Score += 10;
if (Candidate."Direct Unit Cost" <> 0) and (Abs(Candidate."Direct Unit Cost" - PurchLine."Direct Unit Cost") <= AmtTol) then
Score += 10;
if (Candidate."Line Amount" <> 0) and (Abs(Candidate."Line Amount" - PurchLine."Line Amount") <= AmtTol) then
Score += 10;
if (Candidate.Description <> '') and (PurchLine.Description <> '') and (Candidate.Description = PurchLine.Description) then
Score += 5;
if Score > BestScore then begin
BestScore := Score;
BestSqzLine := Candidate;
end;
until Candidate.Next() = 0;
// Guard: avoid picking a random line when nothing matches well.
exit(BestScore >= 30);
end;
}
Hinzufügen eines Feldes in der Validierung (bis Squeeze BC APP Version 1.*)
Im Folgenden wird anhand einer Beispielextension dargestellt, wie man als Entwickler Felder in der Validierung hinzufügen kann.
Benötigte Integration Events inkl. beispielhafter Prozeduren:
codeunit 50100 EventSubs
{
//
//Any header field that you want to transfer to the resulting document, has to be added to the source JSON Object
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure SQZDocMgtOnBeforeAddLineToDocumentJObj(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
AddCustomHeaderFieldsToJson(DocumentJObj, DocHeader);
end;
//
// Any line field that you want to transfer to the resulting document, has to be added to the source JSON Object
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeAddLineJObjToLineJArray', '', false, false)]
local procedure SQZDocMgtOnBeforeAddLineJObjToLineJArray(var LineJObj: JsonObject; DocLine: Record "DXP SQZ Document Line")
begin
AddCustomLineFieldsToJson(LineJObj, DocLine);
end;
//
// [If you want to perform plausibility checks on the newly added header field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnAfterDoHeaderPlausibilityChecks', '', false, false)]
local procedure SQZDocMgtOnBeforeDoHeaderPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocHeader."Customer No.");
end;
//
// [If you want to perform plausibility checks on the newly added line field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnAfterDoLinePlausibilityChecks', '', false, false)]
local procedure SQZDocMgtOnAfterDoLinePlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; DocLine: Record "DXP SQZ Document Line"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocLine."Customer No.");
end;
//
// The value of the previously extended JSON Object now has to saved to the corresponding field in the SQUEEZE Document Line
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeModifySQUEEZEDocumentHeader', '', false, false)]
local procedure SqzDocMgtOnBeforeModifySQUEEZEDocumentHeader(var DocHeader: Record "DXP SQZ Document Header"; RawJson: JsonObject)
var
JSONHelper: Codeunit "DXP Json Helper";
SQZApiTokenMgt: Codeunit "DXP SQZ API Token Mgt.";
TokenMgt: Codeunit TokenMgt;
begin
DocHeader."Customer No." := COPYSTR(JsonHelper.ValAsTxt(RawJson, SQZApiTokenMgt.GetHeaderValueByNameTok(TokenMgt.GetCustomerNoTok()), false), 1, MaxStrLen(DocHeader."Customer No."));
end;
//
// The value of the previously extended JSON Object now has to saved to the corresponding field in the SQUEEZE Document Header
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues', '', false, false)]
local procedure SQZDocMgtOnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues(RowJTok: JsonToken; var DocLine: Record "DXP SQZ Document Line")
var
JSONHelper: Codeunit "DXP Json Helper";
SQZApiTokenMgt: Codeunit "DXP SQZ API Token Mgt.";
TokenMgt: Codeunit TokenMgt;
begin
DocLine."Customer No." := CopyStr(JsonHelper.ValAsTxt(RowJTok.AsObject(), SQZApiTokenMgt.GetCellValueTok(TokenMgt.GetCustomerNoTok()), false), 1, MaxStrLen(DocLine."Customer No."));
end;
//
// The newly added fields now have to be added to the field mapping
// Otherwise the recognized values will be saved as meta data
// This step is necessary to make sure that the fields can be highlighted in the SQUEEZE Viewer
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterInitMapping', '', false, false)]
local procedure SQZApiMgtOnAfterInitMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer]; DocClass: Enum "DXP Document Class")
var
SQZDocHeader: Record "DXP SQZ Document Header";
SQZDocLine: Record "DXP SQZ Document Line";
TokenMgt: Codeunit TokenMgt;
begin
// The standard (without installed extensions) supports one Document Class
case DocClass of
DocClass::"DXP Invoice / Credit Memo":
begin
HeaderMapping.Add(TokenMgt.GetCustomerNoTok(), SQZDocHeader.FieldNo("Customer No."));
LineMapping.Add(TokenMgt.GetCustomerNoTok(), SQZDocLine.FieldNo("Customer No."));
end;
end;
end;
//
// The value in the JSON Object now has to be transferred to the Purchase Header
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Transfer Mgt.", 'OnAfterCreatePurchaseHeader', '', false, false)]
local procedure DocTransferMgtOnAfterCreatePurchaseHeader(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
begin
TransferCustomHeaderFieldFromJsonToPurchaseHeader(JObject, PurchaseHeader);
end;
//
// The value in the JSON Object now has to be transferred to the Purchase Line
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Transfer Mgt.", 'OnBeforeInsertPurchaseLine', '', false, false)]
local procedure DocTransferMgtOnAfterInsertPurchaseLineOnBeforeAddDimensions(var JObjectLine: JsonObject; var PurchaseLine: Record "Purchase Line")
begin
TransferCustomHeaderFieldFromJsonToPurchaseLine(JObjectLine, PurchaseLine);
end;
local procedure TransferCustomHeaderFieldFromJsonToPurchaseHeader(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
var
JsonHelper: Codeunit "DXP Json Helper";
TokenMgt: Codeunit TokenMgt;
begin
PurchaseHeader.Validate("DXP Customer No.", JsonHelper.ValAsTxt(JObject, TokenMgt.GetCustomerNoTok(), false));
PurchaseHeader.Modify();
end;
local procedure TransferCustomHeaderFieldFromJsonToPurchaseLine(var JObjectLine: JsonObject; var PurchaseLine: Record "Purchase Line")
var
JsonHelper: Codeunit "DXP Json Helper";
TokenMgt: Codeunit TokenMgt;
begin
PurchaseLine.Validate("DXP Customer No.", JsonHelper.ValAsTxt(JObjectLine, TokenMgt.GetCustomerNoTok(), false));
end;
local procedure AddCustomHeaderFieldsToJson(var DocumentJObj: JsonObject; SQZDocumentHeader: Record "DXP SQZ Document Header")
var
TokenMgt: Codeunit TokenMgt;
begin
DocumentJObj.Add(TokenMgt.GetCustomerNoTok(), SQZDocumentHeader."Customer No.");
end;
local procedure AddCustomLineFieldsToJson(var LineJObj: JsonObject; SQZDocumentLine: Record "DXP SQZ Document Line")
var
TokenMgt: Codeunit TokenMgt;
begin
LineJObj.Add(TokenMgt.GetCustomerNoTok(), SQZDocumentLine."Customer No.");
end;
[TryFunction]
local procedure CustomerExists(CustomerNo: Code[20])
var
Customer: Record Customer;
begin
Customer.Get(CustomerNo);
end;
local procedure CheckCustomer(var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt."; CustomerNo: Code[20]): Boolean
begin
if CustomerNo = '' then
exit(false);
if not CustomerExists(CustomerNo) then begin
PlausibilityCheck.AddPlausibilityCheckEntry(GetLastErrorText(), Page::"Customer List");
exit(false);
end;
exit(true);
end;
}
Table Extensions:
SQUEEZE 4 BC
tableextension 50100 "SQZ Doc. Header Ext." extends "DXP SQZ Document Header"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
tableextension 50101 "SQZ Doc. Line Ext." extends "DXP SQZ Document Line"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
tableextension 50102 "Purchase Header Ext." extends "Purchase Header"
{
fields
{
field(50100; "DXP Customer No."; Code[20])
{
DataClassification = CustomerContent;
TableRelation = Customer;
Caption = 'DEXPRO Customer No.';
}
}
}
Page Extensions:
SQUEEZE 4 BC
pageextension 50100 "SQZ Document Ext." extends "DXP SQZ Document"
{
layout
{
addafter(BuyFromVendorInternal)
{
field("Customer No. Internal"; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
trigger OnAssistEdit()
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
addafter(BuyFromVendor)
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
trigger OnAssistEdit()
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
}
local procedure MarkField(AppFldNo: Integer; FieldVal: Variant; DocHeader: Record "DXP SQZ Document Header")
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
ViewerResident := GetViewerResident();
ApiMgt.MarkField(AppFldNo, FieldVal, ViewerResident, DocHeader);
end;
}
pageextension 50101 "SQZ Document Sf. Ext." extends "DXP SQZ Document Subform"
{
layout
{
addafter("No.")
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
}
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
pageextension 50102 "Purchase Invoice Ext." extends "Purchase Invoice"
{
layout
{
addafter("Buy-from Vendor No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
pageextension 50103 "Purchase Inv. Sf Ext." extends "Purch. Invoice Subform"
{
layout
{
addafter("No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
Optionale Hilfsobjekte:
codeunit 50101 TokenMgt
{
procedure GetCustomerNoTok(): Text
begin
exit(CustomerNoTok);
end;
var
CustomerNoTok: Label 'customerNo', Locked = true;
}
Hinzufügen eines Feldes in der Validierung (ab Version 2.0)
Im Folgenden wird anhand einer Beispielextension dargestellt, wie man als Entwickler Felder in der Validierung hinzufügen kann (hier: Dokumentenklasse Rechnung/Gutschrift).
Benötigte Integration Events inkl. beispielhafter Prozeduren:
codeunit 50100 EventSubs
{
//
//Any header field that you want to transfer to the resulting document, has to be added to the source JSON Object
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnBeforeAddLineToDocumentJObj', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnBeforeAddLineToDocumentJObj(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
begin
AddCustomHeaderFieldsToJson(DocumentJObj, DocHeader);
end;
//
// Any line field that you want to transfer to the resulting document, has to be added to the source JSON Object
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnBeforeAddLineJObjToLineJArray', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnBeforeAddLineJObjToLineJArray(var LineJObj: JsonObject; DocLine: Record "DXP SQZ Document Line")
begin
AddCustomLineFieldsToJson(LineJObj, DocLine);
end;
//
// [If you want to perform plausibility checks on the newly added header field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoHeaderPlausibilityChecks', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnBeforeDoHeaderPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocHeader."Customer No.");
end;
//
// [If you want to perform plausibility checks on the newly added line field, this is the place]
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoLinePlausibilityChecks', '', false, false)]
local procedure SQZPInvCrdtMemoImplOnAfterDoLinePlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; DocLine: Record "DXP SQZ Document Line"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
begin
CheckCustomer(PlausibilityCheck, DocLine."Customer No.");
end;
//
// The value of the previously extended JSON Object now has to saved to the corresponding field in the SQUEEZE Document Line
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeModifySQUEEZEDocumentHeader', '', false, false)]
local procedure SqzDocMgtOnBeforeModifySQUEEZEDocumentHeader(var DocHeader: Record "DXP SQZ Document Header"; RawJson: JsonObject)
var
JSONHelper: Codeunit "DXP Json Helper";
SQZApiTokenMgt: Codeunit "DXP SQZ API Token Mgt.";
TokenMgt: Codeunit TokenMgt;
begin
DocHeader."Customer No." := COPYSTR(JsonHelper.ValAsTxt(RawJson, SQZApiTokenMgt.GetHeaderValueByNameTok(TokenMgt.GetCustomerNoTok()), false), 1, MaxStrLen(DocHeader."Customer No."));
end;
//
// The value of the previously extended JSON Object now has to saved to the corresponding field in the SQUEEZE Document Header
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues', '', false, false)]
local procedure SQZDocMgtOnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues(RowJTok: JsonToken; var DocLine: Record "DXP SQZ Document Line")
var
JSONHelper: Codeunit "DXP Json Helper";
SQZApiTokenMgt: Codeunit "DXP SQZ API Token Mgt.";
TokenMgt: Codeunit TokenMgt;
begin
DocLine."Customer No." := CopyStr(JsonHelper.ValAsTxt(RowJTok.AsObject(), SQZApiTokenMgt.GetCellValueTok(TokenMgt.GetCustomerNoTok()), false), 1, MaxStrLen(DocLine."Customer No."));
end;
//
// The newly added fields now have to be added to the field mapping
// Otherwise the recognized values will be saved as meta data
// This step is also necessary to make sure that the fields can be highlighted in the SQUEEZE Viewer
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterInitMapping', '', false, false)]
local procedure SQZApiMgtOnAfterInitMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer]; DocClass: Enum "DXP Document Class")
var
SQZDocHeader: Record "DXP SQZ Document Header";
SQZDocLine: Record "DXP SQZ Document Line";
TokenMgt: Codeunit TokenMgt;
begin
case DocClass of
DocClass::"DXP Invoice / Credit Memo":
begin
HeaderMapping.Add(TokenMgt.GetCustomerNoTok(), SQZDocHeader.FieldNo("Customer No."));
LineMapping.Add(TokenMgt.GetCustomerNoTok(), SQZDocLine.FieldNo("Customer No."));
end;
end;
end;
//
// The value in the JSON Object now has to be transferred to the Purchase Header
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Transfer Mgt.", 'OnAfterCreatePurchaseHeader', '', false, false)]
local procedure DocTransferMgtOnAfterCreatePurchaseHeader(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
begin
TransferCustomHeaderFieldFromJsonToPurchaseHeader(JObject, PurchaseHeader);
end;
//
// The value in the JSON Object now has to be transferred to the Purchase Line
//
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Transfer Mgt.", 'OnBeforeInsertPurchaseLine', '', false, false)]
local procedure DocTransferMgtOnAfterInsertPurchaseLineOnBeforeAddDimensions(var JObjectLine: JsonObject; var PurchaseLine: Record "Purchase Line")
begin
TransferCustomHeaderFieldFromJsonToPurchaseLine(JObjectLine, PurchaseLine);
end;
local procedure TransferCustomHeaderFieldFromJsonToPurchaseHeader(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
var
JsonHelper: Codeunit "DXP Json Helper";
TokenMgt: Codeunit TokenMgt;
begin
PurchaseHeader.Validate("DXP Customer No.", JsonHelper.ValAsTxt(JObject, TokenMgt.GetCustomerNoTok(), false));
PurchaseHeader.Modify();
end;
local procedure TransferCustomHeaderFieldFromJsonToPurchaseLine(var JObjectLine: JsonObject; var PurchaseLine: Record "Purchase Line")
var
JsonHelper: Codeunit "DXP Json Helper";
TokenMgt: Codeunit TokenMgt;
begin
PurchaseLine.Validate("DXP Customer No.", JsonHelper.ValAsTxt(JObjectLine, TokenMgt.GetCustomerNoTok(), false));
end;
local procedure AddCustomHeaderFieldsToJson(var DocumentJObj: JsonObject; SQZDocumentHeader: Record "DXP SQZ Document Header")
var
TokenMgt: Codeunit TokenMgt;
begin
DocumentJObj.Add(TokenMgt.GetCustomerNoTok(), SQZDocumentHeader."Customer No.");
end;
local procedure AddCustomLineFieldsToJson(var LineJObj: JsonObject; SQZDocumentLine: Record "DXP SQZ Document Line")
var
TokenMgt: Codeunit TokenMgt;
begin
LineJObj.Add(TokenMgt.GetCustomerNoTok(), SQZDocumentLine."Customer No.");
end;
[TryFunction]
local procedure CustomerExists(CustomerNo: Code[20])
var
Customer: Record Customer;
begin
Customer.Get(CustomerNo);
end;
local procedure CheckCustomer(var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt."; CustomerNo: Code[20]): Boolean
begin
if CustomerNo = '' then
exit(false);
if not CustomerExists(CustomerNo) then begin
PlausibilityCheck.AddPlausibilityCheckEntry(GetLastErrorText(), Page::"Customer List");
exit(false);
end;
exit(true);
end;
}
Table Extensions:
SQUEEZE 4 BC
tableextension 50100 "SQZ Doc. Header Ext." extends "DXP SQZ Document Header"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
tableextension 50101 "SQZ Doc. Line Ext." extends "DXP SQZ Document Line"
{
fields
{
field(50100; "Customer No."; Code[20])
{
TableRelation = Customer;
ValidateTableRelation = false;
Caption = 'Customer No.';
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
tableextension 50102 "Purchase Header Ext." extends "Purchase Header"
{
fields
{
field(50100; "DXP Customer No."; Code[20])
{
DataClassification = CustomerContent;
TableRelation = Customer;
Caption = 'DEXPRO Customer No.';
}
}
}
Page Extensions:
SQUEEZE 4 BC
pageextension 50100 "SQZ Document Ext." extends "DXP SQZ Document v2"
{
layout
{
addafter(BuyFromVendorInternal)
{
field("Customer No. Internal"; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
trigger OnAssistEdit()
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
addafter(BuyFromVendorExternal)
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
trigger OnAssistEdit()
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
MarkField(Rec.FieldNo("Customer No."), Rec."Customer No.", Rec);
end;
trigger OnValidate()
begin
CheckPlausibility();
end;
}
}
}
local procedure MarkField(AppFldNo: Integer; FieldVal: Variant; DocHeader: Record "DXP SQZ Document Header")
var
ApiMgt: Codeunit "DXP SQZ API Mgt.";
ViewerResident: Codeunit "DXP SQUEEZE Viewer Resident";
begin
ViewerResident := GetViewerResident();
ApiMgt.MarkField(AppFldNo, FieldVal, ViewerResident, DocHeader);
end;
}
pageextension 50101 "SQZ Document Sf. Ext." extends "DXP SQZ Document Subform"
{
layout
{
addafter("No.")
{
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Customer No. field.';
}
}
}
}
Zielbeleg (hier: Einkaufsbeleg)
pageextension 50102 "Purchase Invoice Ext." extends "Purchase Invoice"
{
layout
{
addafter("Buy-from Vendor No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
pageextension 50103 "Purchase Inv. Sf Ext." extends "Purch. Invoice Subform"
{
layout
{
addafter("No.")
{
field("DXP Customer No."; Rec."DXP Customer No.")
{
ToolTip = 'Specifies the value of the DEXPRO Customer No. field.';
ApplicationArea = all;
}
}
}
}
Optionale Hilfsobjekte:
codeunit 50101 TokenMgt
{
procedure GetCustomerNoTok(): Text
begin
exit(CustomerNoTok);
end;
var
CustomerNoTok: Label 'customerNo', Locked = true;
}
Regelbasierter nächster Prozessschritt: Belege in „Individuelle Verarbeitung“ steuern
Zielgruppe
Diese Anleitung richtet sich an Entwickler und Implementierer, die DEXPRO SQUEEZE in Business Central einsetzen und vor der eigentlichen „Individuelle Verarbeitung“-Implementierung steuern möchten, welche Belege nach der Validierung in den Status „Individuelle Verarbeitung“ wechseln sollen.
Einordnung (kommt vor der bestehenden Custom-Processing-Anleitung)
Mit dieser Konfiguration sorgst du dafür, dass ein Beleg (abhängig von Regeln) den Status „Individuelle Verarbeitung“ erhält. Ab diesem Zeitpunkt greift dann der in der bestehenden Dokumentation beschriebene Ablauf zur benutzerdefinierten Verarbeitung (Erstellen von Zieldokumenten aus „JSON Processed“).
Weiterführend (nächster Schritt, nach dieser Dokumentation):
Verwendete (UI-)Begriffe
Die nachfolgenden Begriffe entsprechen den deutschen Beschriftungen aus den de-DE Übersetzungen:
- „Individuelle Verarbeitung“ =
DXP Document Status/Custom Processing - „Nächster Prozessschritt“ =
Next Process Step - „Standardbeleg“ = Enum-Wert
Standard document - „Regelsatz“, „Regelsatzcode“ =
Rule Set,Rule Set Code - „Regelgruppe“, „Regelgruppencode“ =
Rule Group,Rule Group Code
Technischer Hintergrund
- Pro Dokumentenklasse gibt es eine Dokumentenklasseneinrichtung (
DXP Document Class Setup). - Für jede Dokumentenklasseneinrichtung wird automatisch ein SQUEEZE-Regelsatz angelegt (intern: Feld „DXP Sqz Rule Set Code“).
- In der Dokumentenklasseneinrichtung wird ein Regelgruppencode hinterlegt (intern: Feld „DXP Sqz Next Step Rule Group“).
- Beim Ermitteln des nächsten Prozessschritts werden die Regeln dieser Regelgruppe ausgewertet.
- Wenn eine Regel zutrifft und
- Nächster Prozessschritt = „Standardbeleg“ und
- Individuelle Verarbeitung = Ja dann wird der Dokumentstatus auf „Individuelle Verarbeitung“ gesetzt.
Wichtig:
- Ist keine Regelgruppe hinterlegt oder keine Regel zutreffend, wird auf den Standardwert „Nächster Prozessschritt“ aus der Dokumentenklasseneinrichtung zurückgefallen.
Voraussetzungen
- DEXPRO Core + DEXPRO SQUEEZE sind installiert.
- Du hast Zugriff auf die Einrichtung Dokumentenklasseneinrichtung (DXP Document Class Setup) sowie auf die Regel-Engine-Seiten (Regelgruppen/Regeln).
Schritt-für-Schritt: Regelgruppe „DXP Sqz Next Step Rule Group“ anlegen und verknüpfen
1) Dokumentenklasseneinrichtung öffnen
- Öffne die Seite Dokumentenklasseneinrichtung.
- Wähle die Dokumentenklasse aus, für die du das Routing auf „Individuelle Verarbeitung“ aktivieren willst.
- Scrolle in den Bereich Squeeze → Gruppe Regeln.
2) Regelgruppe anlegen
- In Squeeze → Rules wähle das Feld „Nächster Prozessschritt“ (technisch: DXP Sqz Next Step Rule Group).
- Öffne die Auswahl/Lookup (Regelgruppenliste).
- Lege eine neue Regelgruppe an:
- Regelgruppencode: z. B.
Next Step Rules - Beschreibung: z. B. „Routing nach Individuelle Verarbeitung“
- Regelgruppencode: z. B.
Hinweis: Der Lookup ist durch die Dokumentenklasse bereits auf den passenden Regelsatzcode gefiltert. Du musst den Regelsatz nicht manuell suchen.
3) Regelgruppe in der Dokumentenklasseneinrichtung speichern
- Stelle sicher, dass in der Dokumentenklasseneinrichtung im Feld „Nächster Prozessschritt“ jetzt der Regelgruppencode
DXP Sqz Next Step Rule Groupsteht.
Schritt-für-Schritt: Regel erstellen, die auf „Individuelle Verarbeitung“ routet
4) Regeln der Regelgruppe öffnen
- Öffne die soeben angelegte Regelgruppe
DXP Sqz Next Step Rule Group. - Wähle die Aktion „Regeln anzeigen“ (öffnet die Regeln dieser Regelgruppe).
5) Neue Regel anlegen
- Lege eine neue Regel an.
- Lege eine sinnvolle Priorität fest (niedriger Wert = höhere Priorität, falls eure Umgebung so konfiguriert ist).
- Definiere die Bedingungen (Rule Conditions), die zutreffen müssen.
[Best Practice] Starte mit einer sehr klaren, testbaren Bedingung (z. B. anhand von Belegtyp, Lieferant, Betragsschwellen, Mandant/Company, etc.), bevor du komplexe Regelketten aufbaust.
6) SQUEEZE-spezifische Felder setzen (entscheidend für „Individuelle Verarbeitung“)
Auf der Regelkarte gibt es den Bereich „DEXPRO Squeeze“ (CardPart). Setze dort:
- Nächster Prozessschritt = „Standardbeleg“
- Individuelle Verarbeitung = Ja
Ergebnis:
- Wenn diese Regel zutrifft, wird der Belegstatus auf „Individuelle Verarbeitung“ gesetzt.
Optional:
- Kontierungscode [Account Assignment Code] (falls du zusätzlich eine Kontierungslogik über Regeln steuern möchtest; unabhängig vom Custom-Processing-Routing).
Prüfen / Troubleshooting
Beleg landet nicht in „Individuelle Verarbeitung“
Gehe diese Punkte durch:
- Regelgruppe hinterlegt? In der Dokumentenklasseneinrichtung muss der Regelgruppencode gesetzt sein (sonst fällt das System auf Standard „Nächster Prozessschritt“ zurück).
- Trifft eine Regel zu? Wenn keine Regel zutrifft, wird der nächste Prozessschritt nicht überschrieben.
- Ist „Individuelle Verarbeitung“ gesetzt UND Next Step = „Standardbeleg“?
- Wenn „Individuelle Verarbeitung“ = Ja, aber Next Step ≠ „Standardbeleg“, wird der Status nicht auf „Individuelle Verarbeitung“ gesetzt.
- Siehst du den Bereich „DEXPRO Squeeze“ auf der Regelkarte nicht?
- Dann befindest du dich sehr wahrscheinlich in einem Regelsatz, der nicht zur Dokumentenklasseneinrichtung (Quelltabelle) gehört.
- Lege die Regelgruppe im besten Fall über den Lookup aus der Dokumentenklasseneinrichtung an. Damit sparst du dir den Weg über die allgemeine Regelverwaltng
Beleg landet in „Fertig“ statt „Individuelle Verarbeitung“
Wenn eine Regel zutrifft und Nächster Prozessschritt auf einen Wert ungleich „Standardbeleg“ gesetzt wird, kann der Status auf „Fertig“ gesetzt werden (damit wird weitere Verarbeitung übersprungen). Prüfe daher die Next-Step-Auswahl in der Regel. Das ist zum Beispiel der Fall, wenn die App Breeze Interface benutzt wird.
Danach (Übergang in die bestehende Doku, zur individuellen Belegerstellung)
Sobald ein Beleg im Status „Individuelle Verarbeitung“ ist, ist es bereit für die Verarbeitung:
- „JSON Processed“ aus
DXP Documentlesen - Zieldokumente erstellen
- finalen Status setzen
Events nach der Erstellung eines SQUEEZE-Belegs (CreateSource)
Zielgruppe
Diese Dokumentation richtet sich an Drittanbieter-Entwickler, die den Erstellungsprozess eines SQUEEZE-Belegs (Tabellen DXP SQZ Document Header/DXP SQZ Document Line) erweitern möchten.
Im Fokus stehen die Integration Events, die nach bzw. während ISourceDocument.CreateSource(...) ausgelöst werden.
Einordnung: Wo wird CreateSource aufgerufen?
Der Einstiegspunkt für die SQUEEZE-Integration ist in der Codeunit DXP SQZ API Mgt.:
- Es wird ein Core-Beleg (
DXP Document) angelegt (überDXP Document Mgt.). - Anschließend wird über die Dokumentenklasse das Interface
DXP ISource Documentaufgelöst undCreateSource(Document)ausgeführt.
Vereinfachter Ablauf (aus CreateCoreAndSQUEEZEDocument):
DocumentMgt.AddDocument(DocClass, ...)(Core-Beleg anlegen)ISourceDocument.CreateSource(Document)(SQUEEZE-Beleg erzeugen)- Import-Queue verarbeiten / SQUEEZE-Dokument „finishen“
Dokumentenklassen & Default-Verhalten
Welche CreateSource-Implementierung ausgeführt wird, ist in der Enum-Erweiterung DXP Document Class Ext. hinterlegt.
DXP Invoice / Credit Memo→ CodeunitDXP SQZ P. Inv/Crdt Memo Impl.DXP Order Confirmation→ CodeunitDXP SQZ P. Order Conf. Impl.
Default (wenn keine spezifische Implementierung gesetzt ist): Die Enum DXP Document Class definiert eine DefaultImplementation auf DXP Source Document Def. Impl.. Diese Default-Implementierung:
- erzeugt keinen SQUEEZE-Beleg,
CreateSource(...)gibtfalsezurück.
Gemeinsame Pipeline innerhalb CreateSource
Beide SQUEEZE-Implementierungen folgen (verkürzt) diesem Muster:
- Guard: Core-Dokument muss
Status = Importedhaben undJSON Rawmuss existieren. DXP SQZ Document Mgt.:CreateSQUEEZEDocHeader(Document, DocHeader, RawJson)CreateSQUEEZEDocLine(DocHeader, RawJson)
DXP Document Mgt.:UpdateDocumentAfterTransfer(...)(Core-Dokument auf „Transferred“ setzen und mit SQZ-Header verknüpfen)- Ordermatch / Autocomplete / Attachments / Validierung (abhängig von Dokumentenklasse und Setup)
Die wichtigsten Events hängen daher an:
- der Header-/Line-Erzeugung in
DXP SQZ Document Mgt. - dem Abschluss der
CreateSource-Prozedur in den jeweiligen Implementierungen - optionalen Schritten wie Ordermatch oder Validierung
Event-Matrix (Kurzüberblick)
| Bereich | Event | Zeitpunkt | Steuerung | Typische Use-Cases |
|---|---|---|---|---|
DXP SQZ API Mgt. |
OnAfterInitMapping(...) |
nach Initialisierung Mapping/Token-Kontext | – | Mapping erweitern/prüfen |
DXP SQZ API Mgt. |
OnAfterSaveAttachment(...) |
nach erfolgreichem Speichern eines Attachments | – | Nachverarbeitung/Indexierung |
DXP SQZ API Mgt. |
OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment(...) |
vor dem Modify des Attachment-Datensatzes | – | Dateiname/Origin beeinflussen |
DXP SQZ P. Inv/Crdt Memo Impl. |
OnAfterCreateDocLines |
direkt nach CreateSQUEEZEDocLine(...) |
– | Lines/RawJson nach Anlage auswerten |
DXP SQZ P. Inv/Crdt Memo Impl. |
OnAfterCreateSource |
am Ende von CreateSource(...) |
– | Post-Aktionen nach Autocomplete/Ordermatch/Validierung |
DXP SQZ P. Inv/Crdt Memo Impl. |
OnBeforeDoPlausibilityChecks |
vor Plausibilitätschecks | IsHandled |
Checks ersetzen/erweitern |
DXP SQZ P. Inv/Crdt Memo Impl. |
OnAfterDoPlausibilityChecks |
nach Plausibilitätschecks | – | Ergebnis weiterverwenden (Entries) |
DXP SQZ P. Order Conf. Impl. |
OnBeforeDoPlausibilityChecks |
vor Plausibilitätschecks | IsHandled |
Checks ersetzen/erweitern |
DXP SQZ Document Mgt. |
OnBeforeModifySQUEEZEDocumentHeader |
in CreateSQUEEZEDocHeader(...) vor finalem Modify |
– | Headerwerte aus RawJson ergänzen/normalisieren |
DXP SQZ Document Mgt. |
OnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues |
im Standard-Line-Post-Processing vor TransferRecognizedValues |
– | erkannte Werte pro Line korrigieren |
DXP SQZ Document Mgt. |
OnAfterTransferRecognizedValuesOnBeforeInsertDocLine |
im Standard-Line-Post-Processing nach TransferRecognizedValues |
– | line-basierte Ableitungen (Kontierung/Dimensionen) |
DXP SQZ Document Mgt. |
OnBeforePerformAutomaticOrdermatch |
vor automatischem Ordermatch | IsHandled |
Ordermatch komplett übernehmen/OrderNoList anpassen |
| JSON-Erzeugung | OnBeforeAddLineToDocumentJObj |
vor dem Aufbau der Line-Struktur | – | Header-JSON erweitern |
| JSON-Erzeugung | OnBeforeAddLineJObjToLineJArray |
vor LineJArray.Add(LineJObj) |
– | Line-JSON erweitern |
Events in DXP SQZ P. Inv/Crdt Memo Impl. (Dokumentenklasse: Invoice / Credit Memo)
Diese Codeunit bietet die stärksten Erweiterungspunkte direkt im CreateSource-Ablauf.
OnAfterCreateDocLines
Wird direkt nach CreateSQUEEZEDocLine(...) ausgelöst (also nachdem Header & Lines existieren).
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterCreateDocLines(DocHeader: Record "DXP SQZ Document Header"; RawJson: JsonObject)
Typische Use-Cases:
- zusätzliche Initialisierung am Header (z. B. eigene Flags/Felder)
- zusätzliche line-basierte Auswertungen direkt nach Anlage
- eigene Metadaten aus
RawJsonextrahieren
OnAfterCreateSource
Wird am Ende von CreateSource(...) ausgelöst (nach Autocomplete/Ordermatch/optionalem Attachment-Download/optionalem Auto-Validate).
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterCreateSource(DocHeader: Record "DXP SQZ Document Header"; RawJson: JsonObject)
Typische Use-Cases:
- nachgelagerte Automatisierungen starten (Workflows, Benachrichtigungen)
- zusätzliche Datenvalidierung oder eigene Statuslogik
Plausibilitätsprüfung-Events
Diese Events betreffen die Methode IsSourceDataPlausible(...) und sind relevant, wenn ihr Plausibilitätschecks erweitert/ersetzt.
Signaturen (Auszug):
[IntegrationEvent(false, false)]
local procedure OnBeforeDoPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary; var IsHandled: Boolean)
[IntegrationEvent(false, false)]
local procedure OnBeforeDoHeaderPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
[IntegrationEvent(false, false)]
local procedure OnBeforeDoLinePlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; DocLine: Record "DXP SQZ Document Line"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.")
[IntegrationEvent(false, false)]
local procedure OnAfterDoPlausibilityChecks(DocHeader: Record "DXP SQZ Document Header"; var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary)
JSON-Erzeugung (Processed JSON aus dem SQZ-Beleg)
Die Implementierung enthält Events, bevor Line-JSON zur Header-Struktur hinzugefügt wird:
OnBeforeAddLineToDocumentJObj
[IntegrationEvent(false, false)]
local procedure OnBeforeAddLineToDocumentJObj(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
OnBeforeAddLineJObjToLineJArray
[IntegrationEvent(false, false)]
local procedure OnBeforeAddLineJObjToLineJArray(var LineJObj: JsonObject; DocLine: Record "DXP SQZ Document Line")
Use-Cases:
- zusätzliche Felder ins Header-JSON schreiben
- zusätzliche Felder pro Line ergänzen (Custom Tokens)
Events in DXP SQZ P. Order Conf. Impl. (Dokumentenklasse: Order Confirmation)
Diese Codeunit hat keine dedizierten OnAfterCreateSource-Events in CreateSource(...). Erweiterungen passieren hier typischerweise über:
DXP SQZ Document Mgt.(Header/Line-Erzeugung, Ordermatch)- die JSON-Erzeugung (
CreateProcessedJsonFromSource) - Plausibilitätsprüfung-Events
JSON-Erzeugung
[IntegrationEvent(false, false)]
local procedure OnBeforeAddLineToDocumentJObj(var DocumentJObj: JsonObject; DocHeader: Record "DXP SQZ Document Header")
[IntegrationEvent(false, false)]
local procedure OnBeforeAddLineJObjToLineJArray(var LineJObj: JsonObject; DocLine: Record "DXP SQZ Document Line")
Plausibilitätsprüfung-Events
Analog zur Invoice/Credit-Memo-Implementierung:
OnBeforeDoPlausibilityChecksOnBeforeDoHeaderPlausibilityChecksOnBeforeDoLinePlausibilityChecksOnAfterDoPlausibilityChecks
Events in DXP SQZ Document Mgt. (gemeinsam für alle Dokumentenklassen)
Diese Events sind besonders relevant, weil sie innerhalb der Header/Line-Erzeugung und Ordermatch-Pipeline ausgelöst werden.
OnBeforeModifySQUEEZEDocumentHeader
Wird in CreateSQUEEZEDocHeader(...) ausgelöst, nachdem Werte über Field Mapping zugewiesen wurden und bevor der Header final modifiziert wird.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeModifySQUEEZEDocumentHeader(var DocHeader: Record "DXP SQZ Document Header"; RawJson: JsonObject)
Use-Cases:
- Header-Felder anpassen, bevor Standard-Post-Processing läuft
- zusätzliche Werte aus
RawJsonin den Header übernehmen
OnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues
OnAfterTransferRecognizedValuesOnBeforeInsertDocLine
Werden im Standard-Line-Post-Processing (für Standard-Dokumentenklassen) um TransferRecognizedValues(DocLine) herum ausgelöst.
Signaturen:
[IntegrationEvent(false, false)]
local procedure OnBeforeTransferRecognizedValuesOnAfterAssignRecognizedValues(var DocLine: Record "DXP SQZ Document Line"; RowJTok: JsonToken)
[IntegrationEvent(false, false)]
local procedure OnAfterTransferRecognizedValuesOnBeforeInsertDocLine(var DocLine: Record "DXP SQZ Document Line")
Use-Cases:
- erkannte Werte pro Line korrigieren/normalisieren
- zusätzliche Ableitungen (z. B. Kontierung, Dimensionen) vorbereiten
OnBeforePerformAutomaticOrdermatch
Wird in PerformAutomaticOrdermatch(...) ausgelöst, nachdem die Order-Nummern-Liste (OrderNoList) gefüllt wurde und bevor der automatische Ordermatch läuft.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforePerformAutomaticOrdermatch(DocHeader: Record "DXP SQZ Document Header"; var OrderNoList: List of [Code[20]]; var IsHandled: Boolean)
Use-Cases:
- automatische Ordermatch-Logik komplett übernehmen (
IsHandled := true) - OrderNoList anpassen (z. B. filtern/ergänzen)
Events in DXP SQZ API Mgt. (kontextnah zur Anlage/Attachments)
Diese Events liegen „um“ die API-Kommunikation herum (z. B. Attachments).
OnAfterInitMapping
Wird in DownloadFieldMapping(...) ausgelöst, nachdem die Dokumentenklasse über das Interface DXP ISource Document das Default-Mapping initialisiert hat (ISourceDocument.InitFieldMapping(...)) und bevor die Feldliste aus SQUEEZE in die BC-Field-Mapping-Strukturen synchronisiert wird.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterInitMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer]; DocClass: Enum "DXP Document Class")
Parameter:
HeaderMapping/LineMapping: Dictionaries mit Default-Zuordnung SQZ-Feldname → BC-Feldnr. (übervarveränderbar)DocClass: Dokumentenklasse, für die das Mapping geladen wird
Typische Use-Cases:
- zusätzliche (kundenspezifische) Feldnamen als Default-Mapping ergänzen
- Default-Mapping korrigieren (z. B. wenn sich SQZ-Feldnamen geändert haben)
- Mapping-Validierung/Logging je Dokumentenklasse
OnAfterSaveAttachment
Wird in SaveAttachments(...) pro Attachment ausgelöst, nachdem das Attachment über DXP Document Attachment Mgt. angelegt wurde und – falls das Attachment als Origin-Datei markiert ist – nach dem Modify(true) des Datensatzes.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterSaveAttachment(DocumentAttachment: Record "DXP Document Attachment")
Hinweis:
DocumentAttachmentwird nicht alsvarübergeben. Wenn ihr Felder am Datensatz persistent ändern möchtet, müsst ihr im Subscriber den Datensatz erneut laden und explizitModify(...)ausführen.
Typische Use-Cases:
- Attachment extern indexieren/archivieren
- Metadaten ableiten (z. B. Klassifizierung nach MIME-Type/Dateiendung)
- Folgeprozesse triggern (z. B. OCR/Preview-Generierung in Drittsystem)
OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment
Wird in SaveAttachments(...) ausgelöst, wenn das Attachment laut Payload als Origin-Datei markiert ist und nachdem Is Source File sowie File Name (Origin-Name) gesetzt wurden – aber bevor DocumentAttachment.Modify(true) aufgerufen wird.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment(var DocumentAttachment: Record "DXP Document Attachment")
Typische Use-Cases:
- Origin-Dateinamen normalisieren (z. B. verbotene Zeichen entfernen, Namensschema erzwingen)
- zusätzliche Felder am Attachment setzen, bevor gespeichert wird
Minimalbeispiele: EventSubscriber für DXP SQZ API Mgt.
Die folgenden Beispiele zeigen typische, kleine Erweiterungen. Passt Objekt-IDs/Namen an euren Namespace an.
codeunit 50101 "My SQZ API Mgt. Subs"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterInitMapping', '', false, false)]
local procedure OnAfterInitMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer]; DocClass: Enum "DXP Document Class")
var
SqzDocHeader: Record "DXP SQZ Document Header";
SqzDocLine: Record "DXP SQZ Document Line";
begin
// Beispiel: neues SQZ-Feld als Default-Mapping ergänzen.
// Wichtig: Der Integer-Wert ist die BC-Feldnr. des Ziel-Feldes (abhängig von eurem Mapping-Konzept).
if not HeaderMapping.ContainsKey('my_custom_header_token') then
HeaderMapping.Add('my_custom_header_token', SqzDocHeader.FieldNo("Vendor No."));
if not LineMapping.ContainsKey('my_custom_line_token') then
LineMapping.Add('my_custom_line_token', SqzDocLine.FieldNo(Description));
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment', '', false, false)]
local procedure OnAfterSetOriginFileNameOnBeforeModifyDocumentAttachment(var DocumentAttachment: Record "DXP Document Attachment")
begin
// Beispiel: Origin-Dateiname normalisieren (Whitespace entfernen).
DocumentAttachment."File Name" := DelChr(DocumentAttachment."File Name", '=', ' ');
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ API Mgt.", 'OnAfterSaveAttachment', '', false, false)]
local procedure OnAfterSaveAttachment(DocumentAttachment: Record "DXP Document Attachment")
begin
// Beispiel: Nachverarbeitung anstoßen.
// Falls ihr persistent am Attachment ändern wollt, könnt ihr den Parameter-Datensatz auch direkt modifizieren.
// DocumentAttachment.Validate("Your Field", ...);
// DocumentAttachment.Modify(true);
end;
}
Events nach der Erstellung eines Core-Belegs (DXP Document)
Zielgruppe
Diese Dokumentation richtet sich an Drittanbieter-Entwickler, die den Lebenszyklus des Core-Belegs DXP Document erweitern möchten – insbesondere an den Punkten, an denen:
- Status / „Nächster Prozessschritt“ bewertet wird,
JSON Raw/JSON Processedaktualisiert wird,- Standardbelege erzeugt werden (z. B. Einkaufsbelege),
- Attachments übertragen werden.
Einordnung: Core-Beleg-Erstellung vs. Weiterverarbeitung
1) Core-Beleg wird angelegt (AddDocument)
Die Anlage eines DXP Document erfolgt in DXP Document Mgt. über AddDocument(...):
- Status wird auf Imported gesetzt.
JSON Rawwird (falls vorhanden) in ein BLOB-Feld geschrieben.
2) Danach: Transfer/Verknüpfung und Verarbeitung
Typische nächste Schritte (abhängig vom App-Flow):
- Verknüpfung mit einem Quellbeleg (z. B. SQUEEZE Header) über
UpdateDocumentAfterTransfer(...) - Erzeugung eines Standardbelegs und Schreiben des
JSON ProcessedüberUpdateDocument(...)
Die meisten Erweiterungspunkte liegen daher nicht direkt beim Insert, sondern im Update-/Processing-Flow.
Event-Matrix (Kurzüberblick)
| Bereich | Event | Zeitpunkt | Steuerung | Typische Use-Cases |
|---|---|---|---|---|
DXP Document Mgt. |
OnAfterSetLinkedToRecIdOnBeforeModify |
in UpdateDocumentAfterTransfer(...) vor Modify(true) |
– | Zusatzinfos setzen, sobald Linked-to Record Id steht |
DXP Document Mgt. |
OnBeforeGetDocumentOnBeforeCheckStatusAndNextProcessStep |
früh in UpdateDocument(...) vor Document.Get(DocNo) |
IsHandled |
Status/NextStep überschreiben, Processing übernehmen |
DXP Document Mgt. |
OnAfterGetDocumentOnBeforeCheckStatusAndNextProcessStep |
in UpdateDocument(...) nach Get(...) vor Standardbeleg-Erzeugung |
Handled |
abhängig vom Dokument entscheiden, JSON/Status anpassen |
DXP Document Mgt. |
OnAfterUpdateRawJson |
nach Schreiben von JSON Raw in UpdateRawJsonJson(...) |
– | Raw JSON normalisieren/zusätzliche Ableitungen |
DXP Document Mgt. |
OnAfterWriteProcessedJsonToBlob |
nach Schreiben von JSON Processed in UpdateStatusAndProcessedJson(...) |
– | Processed JSON finalisieren, Tokens ergänzen |
DXP Document Mgt. |
OnBeforeTransferCoreAttachmentsToStandardDocument |
vor Attachment-Transfer | IsHandled |
Transfer ersetzen/selektiv steuern |
DXP Document Transfer Mgt. |
OnBeforeExitProcessedJsonDocHeader |
beim Erzeugen von Header-JSON (vor exit(JObject)) |
– | Standard-Tokens ergänzen/normalisieren |
DXP Document Transfer Mgt. |
OnBeforeExitProcessedJsonDocLine |
beim Erzeugen von Line-JSON (vor exit(JObject)) |
– | Line-Tokens ergänzen/normalisieren |
DXP Document Transfer Mgt. |
OnAfterCreatePurchaseHeader |
nach Anlage/Validierung des Purchase Headers | – | Header-Felder ergänzen, Post-Processing |
DXP Document Transfer Mgt. |
OnBeforeInsertPurchaseLine |
vor Insert einer Purchase Line | – | Purchase Line anpassen (z. B. Kontierung, Typ/No) |
DXP Document Transfer Mgt. |
OnAfterInsertPurchaseLineOnBeforeAddDimensions |
nach Insert, vor Dimensionen | – | Dimensions/Additional-Info vorbereiten |
DXP Document Transfer Mgt. |
OnAfterOnBeforeAddLineDimensions |
bei Receipt-Lines: vor Dimensionen des zu aktualisierenden Lines | – | Update-Fälle (Receipt) anpassen |
DXP Document Transfer Mgt. |
OnAfterProcessAdditionalInformation |
nach Transfer zusätzlicher Informationen | – | Add-on-Felder pro Ziel-RecordRef ergänzen |
DXP Document Transfer Mgt. |
OnAfterCreatePurchaseDoc |
nach kompletter Erstellung des Purchase Dokuments | – | finaler Hook (Logging, Folgeaktionen) |
Events in DXP Document Mgt. (Core-Lebenszyklus)
OnAfterSetLinkedToRecIdOnBeforeModify
Wird in UpdateDocumentAfterTransfer(...) ausgelöst – nachdem Status/Linked-to Record Id gesetzt wurden, aber bevor das DXP Document gespeichert wird.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterSetLinkedToRecIdOnBeforeModify(var Document: Record "DXP Document")
Use-Cases:
- Zusatzinformationen am Core-Beleg setzen, sobald er auf einen Quellbeleg verlinkt ist
- eigene Logging-/Audit-Informationen ergänzen
OnBeforeGetDocumentOnBeforeCheckStatusAndNextProcessStep
Wird in UpdateDocument(...) als frühester Hook aufgerufen – noch bevor das DXP Document per Get(DocNo) geladen wird.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeGetDocumentOnBeforeCheckStatusAndNextProcessStep(
DocNo: Code[20];
var Status: Enum "DXP Document Status";
var NextStep: Enum "DXP Next Process Step";
JObject: JsonObject;
var IsHandled: Boolean)
Use-Cases:
- Status/NextStep vorab überschreiben (z. B. „Individuelle Verarbeitung“)
- komplette Verarbeitung übernehmen (
IsHandled := true)
OnAfterGetDocumentOnBeforeCheckStatusAndNextProcessStep
Wird in UpdateDocument(...) nach Document.Get(DocNo) ausgelöst, bevor Standardbelege erzeugt werden.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterGetDocumentOnBeforeCheckStatusAndNextProcessStep(
var Document: Record "DXP Document";
NewStatus: Enum "DXP Document Status";
NextStep: Enum "DXP Next process step";
var ProcessedJSONObj: JsonObject;
var Handled: Boolean)
Use-Cases:
- abhängig vom aktuellen Core-Dokument entscheiden, ob Processing übernommen werden soll
- Anpassungen am
ProcessedJSONObjvor der weiteren Verarbeitung
OnAfterUpdateRawJson
Wird in UpdateRawJsonJson(...) nach dem Schreiben von JSON Raw ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateRawJson(var Document: Record "DXP Document"; var RawJSONObj: JsonObject)
Use-Cases:
- Validierungs-/Normalisierungsschritte auf
RawJSONObj - zusätzliche Datenextraktion direkt nach Raw-Update
OnAfterWriteProcessedJsonToBlob
Wird in UpdateStatusAndProcessedJson(...) ausgelöst, nachdem JSON Processed in das BLOB geschrieben wurde.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterWriteProcessedJsonToBlob(var Document: Record "DXP Document"; var ProcessedJSONObj: JsonObject)
Use-Cases:
- zusätzliche Tokens ergänzen
- Datenstruktur finalisieren, bevor nachgelagerte Prozesse darauf zugreifen
OnBeforeTransferCoreAttachmentsToStandardDocument
Wird in TransferCoreAttachmentsToStandardDocument(...) vor dem Transfer ausgelöst. Über IsHandled kann die Standardlogik ersetzt werden.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeTransferCoreAttachmentsToStandardDocument(Document: Record "DXP Document"; var IsHandled: Boolean)
Use-Cases:
- Attachment-Transfer komplett übernehmen (z. B. andere Ablage/Benennung)
- Transfer selektiv einschränken
Events in DXP Document Transfer Mgt. (Standardbelege aus JSON Processed)
Diese Codeunit ist relevant, sobald aus JSON Processed Standardbelege (z. B. Einkaufsbelege) erzeugt werden.
OnBeforeExitProcessedJsonDocHeader
Wird in CreateDocHeaderJson(...) unmittelbar vor exit(JObject) ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeExitProcessedJsonDocHeader(var JObject: JsonObject)
Use-Cases:
- zusätzliche Standard-Tokens ergänzen
- Token-Werte normalisieren (z. B. Typ-/Textdarstellung)
OnBeforeExitProcessedJsonDocLine
Wird in CreateDocLineJson(...) unmittelbar vor exit(JObject) ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeExitProcessedJsonDocLine(var JObject: JsonObject)
Use-Cases:
- Line-Tokens ergänzen/normalisieren
OnAfterCreatePurchaseHeader
Wird nach Anlage/Validierung des Purchase Headers ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterCreatePurchaseHeader(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
Use-Cases:
- zusätzliche Felder am
Purchase Headersetzen (z. B. eigene Referenzen) - Post-Processing/Logging
OnBeforeInsertPurchaseLine
Wird unmittelbar vor dem Insert einer Purchase Line ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnBeforeInsertPurchaseLine(var JObjectLine: JsonObject; var PurchaseLine: Record "Purchase Line")
Use-Cases:
- Purchase Line anpassen (z. B. Kontierung, Typ/No)
OnAfterInsertPurchaseLineOnBeforeAddDimensions
Wird nach Insert der Purchase Line, aber vor Dimensions-Validierung ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterInsertPurchaseLineOnBeforeAddDimensions(var JObjectLine: JsonObject; PurchaseLine: Record "Purchase Line")
Use-Cases:
- Dimensions/Additional-Info vorbereiten
OnAfterOnBeforeAddLineDimensions
Wird im Receipt-Line-Update-Fall ausgelöst, bevor Dimensionen für die zu aktualisierende Purchase Line gesetzt werden.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterOnBeforeAddLineDimensions(var JObjectLine: JsonObject; PurchaseLineToUpdate: Record "Purchase Line")
Use-Cases:
- Update-Fälle (Receipt) anpassen
OnAfterProcessAdditionalInformation
Wird nach dem Transfer zusätzlicher Informationen (ProcessAdditionalInformation) ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterProcessAdditionalInformation(var RecRef: RecordRef; SourceJsonObject: JsonObject)
Use-Cases:
- Add-on Felder für unterschiedliche Zieltabellen (Header/Line) ergänzen
OnAfterCreatePurchaseDoc
Wird nach kompletter Erstellung des Purchase Dokuments ausgelöst.
Signatur:
[IntegrationEvent(false, false)]
local procedure OnAfterCreatePurchaseDoc(var JObject: JsonObject; PurchaseHeader: Record "Purchase Header")
Use-Cases:
- finaler Hook (Post-Processing, Logging, Folgeaktionen)
Minimalbeispiel: Status/NextStep in Richtung „Individuelle Verarbeitung“ beeinflussen
Beispiel: Vor dem Standard-Processing Status auf „Custom Processing“ setzen:
codeunit 50101 "My Core Document Hooks"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Mgt.", 'OnBeforeGetDocumentOnBeforeCheckStatusAndNextProcessStep', '', false, false)]
local procedure OnBeforeGetDoc(
DocNo: Code[20];
var Status: Enum "DXP Document Status";
var NextStep: Enum "DXP Next Process Step";
JObject: JsonObject;
var IsHandled: Boolean)
begin
Status := Status::"Custom Processing";
// NextStep optional anpassen
end;
}
[Best Practice] Nutze IsHandled := true nur, wenn du die Standardlogik vollständig ersetzt – sonst kann es zu inkonsistenten Status-/JSON-Zuständen kommen.
FAQ
Hier finden sie Fragen und Antworten zu verschiedenen Szenarien.
Stammdaten können nicht synchronisiert werden
Prüfen der Squeeze Stammdatentabellen in BC
In der Einrichtung zu den Squeeze Stammdatentabellen sehen Sie welche Stammdaten Tabellen synchronisiert werden sollen, bzw. schon synchronisiert worden sind. Dort können Sie auch für einzelne Tabellen die Synchronisation gen Squeeze deaktivieren.
Prüfen der Squeeze Stammdaten
Auf der Squeeze Seite können Sie prüfen, ob alle Stammdatentabellen bereits vorhanden sind. Sollten welche fehlen, so kann es zu einem 404 Fehler beim Synchronisierungsversuch kommen. Dies wird in der aktuellsten App Version umgangen, indem die Tabelle im Zweifelsfall nachträglich in Squeeze angelegt wird.
Prüfen der Einrichtungen
Squeeze Einrichtung
Stimmt die Squeeze URL überein? Ist das korrekte Squeeze System hinterlegt? Prüfen Sie hierfür die URL.
Wie ist der Verbindungsstatus? Ist der Haken grün? Wenn nicht holen Sie sich einen aktuellen API Schlüssel.
Hat der initiale Stammdaten-Upload bereits stattgefunden?
Dokumentenklassen Einrichtung
Stimmen die API Einstellungen der Dokumentenklasse? Bitte prüfen Sie ob die eingetragenen Ids mit denen auf der DEXPRO Plattform überein stimmen.
Prüfen der Dokumentenklassen Id
Prüfen der Export Schnittstellen Id
Prüfen der Line Table Id
Belege werden nicht aus Squeeze abgeholt und verbleiben dort im Export Schritt
Prüfen der Importwarteschlange
Gibt es bereits einen Eintrag in der Importwarteschlange mit der Squeeze docId? Bitte beim Prüfen die Systemfilterung ebenfalls entfernen.
Nach klicken auf "Systemfilter anzeigen" werden die Systemfilter eingeblendet.
Sobald diese Filter entfernt worden sind, werden alle Belege mandantenübergreifend angezeigt. Prüfen Sie, ob die Squeeze docid in der Spalte "Beleg Id" vorhanden und ob der Eintrag bereits verarbeitet worden ist. Wenn ja, kann dieser nicht erneut runtergeladen werden. Dann muss der Beleg auf der Squeeze Seite (DEXPRO Plattform) manuell in den Schritt "Verarbeitet" gesetzt werden.
Sollte der Beleg nicht in der Liste sein, so kann der nicht abgeholte Beleg über den Importpuffer direkt gezogen werden.
Prüfen der Einrichtungen
Squeeze Einrichtung
Stimmt die Squeeze URL überein? Ist das korrekte Squeeze System hinterlegt? Prüfen Sie hierfür die URL.
Wie ist der Verbindungsstatus? Ist der Haken grün? Wenn nicht holen Sie sich einen aktuellen API Schlüssel.
Dokumentenklassen Einrichtung
Stimmen die API Einstellungen der Dokumentenklasse? Bitte prüfen Sie ob die eingetragenen Ids mit denen auf der DEXPRO Plattform überein stimmen.
Prüfen der Dokumentenklassen Id
Prüfen der Export Schnittstellen Id
Prüfen der Line Table Id