Workaround-Frage für Fehler: Alte Datensatzversion

16. März 2017 13:41

Hallo,

gerade durch die Verwendung von Events kann es schnell passieren, dass man einen ungeschriebenen Record (noch kein modify erfolgt) in einer eigenen Instanz "überschreibt" und daher folgenden Fehler erhält:

mstsc_2017-03-16_10-24-01.png
„Es wurde versucht, eine alte version eines Datensatzes vom Typ Verkaufskopf zu ändern. Der Datensatz muss zunächst erneut aus der Datenbank gelesen werden."

Ein einfaches Beispiel dazu:

Ich abonniere das OnBeforePostSalesDoc Event um mit dem SalesHeader eine Routine anzustoßen, welche den Beleg anhand von Debitoreinstellungen versendet (Als PDF,XML,... per Mail,Ftp,...).
In stark vereinfachter Form schaut das so aus:

Code:
LOCAL [EventSubscriber] OnBeforePostSalesDoc(VAR SalesHeader : Record "Sales Header")

SalesHeader.SETRECFILTER;
REPORT.SAVEASPDF(205, FileMngmt.ServerTempFileName('pdf'), SalesHeader);

Der SalesHeader vom Event enthält die ungeschriebenen Informationen "Ship" und/oder "Invoice" (+ ein paar mehr) vom vorausgegangenen Buchungsdialog.
Wenn die PDF erstellt wird, dann wird der "Anzahl gedruckt" Zähler im neu aus der Datenbank geladenen Record hochgesetzt. Demzufolge fehlen auch die bereits gemachten Änderungen. Es kommt zu oben abgebildetem Fehler.

Workaround:
Man kann den Fehler ganz leicht umgehen indem man die Recordänderungen am SalesHeader wieder mit der ungeschriebenen Ursprungsversion vom Event überschreibt. Dazu ergänzt man den Code um 3 weitere Zeilen:

Code:
LOCAL [EventSubscriber] OnBeforePostSalesDoc(VAR SalesHeader : Record "Sales Header")

SalesHeader.SETRECFILTER;
REPORT.SAVEASPDF(205, FileMngmt.ServerTempFileName('pdf'), SalesHeader);   

//Die eigenen Änderungen verwerfen
SalesHeader2.GET(SalesHeader."Document Type",SalesHeader."No.");
SalesHeader2.TRANSFERFIELDS(SalesHeader,FALSE);
SalesHeader := SalesHeader2;


Alle durch den Druck gemachten Änderungen (Erhöhung des Druckzählers) sind somit wieder verschwunden. Man müsste selbst dafür sorgen, dass die eigenen Änderungen gespeichert werden. In diesem Fall also mit einer letzten zusätzlichen Zeile:
Code:
SalesHeader."No. Printed" += 1;


Meine Frage wäre nun, ob man das so machen kann bzw. darf oder ob dann doch eine andere Lösung sinnvoller wäre?
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Workaround-Frage für Fehler: Alte Datensatzversion

16. März 2017 17:48

vandyke hat geschrieben:Meine Frage wäre nun, ob man das so machen kann bzw. darf oder ob dann doch eine andere Lösung sinnvoller wäre?


Im Prinzip sollte das so klappen...

Eigentlich sollte in dem Fall aber auch das reichen:
Code:
SalesHeader.GET


Dann lädt er den Datensatz erneut und somit sollte man keinen Fehler mehr bekommen.
Kann es gerade nicht testen, aber es sollte eigentlich funktionieren.

Grüße
:wink:

Re: Workaround-Frage für Fehler: Alte Datensatzversion

20. März 2017 14:50

tr1ckkyyy hat geschrieben:Eigentlich sollte in dem Fall aber auch das reichen:
Code:
SalesHeader.GET


Nein, das geht nicht. Denn dann fehlen ja die bisherigen, noch nicht geschriebenen Informationen wie Ship und Invoice.

Re: Workaround-Frage für Fehler: Alte Datensatzversion

20. März 2017 15:21

Hallo,

auch wenn MS das anders sieht, aber "Ship" und "Invoice" sind temporäre Variablen im Salesheader. Sie haben einzig und allein die Aufgabe, die Buchungsart an CU 80 bzw. CU 90 zu übergeben.
Zu etwas anderes sind die nicht zu gebrauchen.
Da in CU 80 und CU90 bzw. in daraus aufgerufenen Objekten unter bestimmten Bedingungen Modifiys und COMMITs enthalten sind, kann man sich nicht darauf verlassen, dass die Flags die Warheit sagen, wenn später in den CUs ein Fehler auftritt ein Fehler.
Mal ganz davon abgesehen, das ein teilweise berechneter Auftrag "Invoice" nicht unbedingt gesetzt haben muss, wenn später eine weitere Teillieferung erfolgt, und nur noch "Ship" gesetzt ist,.....

Woraus auch folgt, dass die Queues im Rollencenter in älteren RTC Versionen Murks anzeigen, wenn der Mandant mit Teillieferungen/- Berechnungen arbeitet.

Nun aber zu dem Problem:

Das ganze funktioniert nur dann ohne Probleme, wenn von vorne bis hinten sichergestellt ist, dass das System mit dem gleichen Salesheader arbeitet, also keine weiteren Salesheader verwendet werden in den aufgerufenen Objekten und Parameterübergabe immer als VAR. Ein Modify darf dann nur auf den übergeben Record gemacht werden, bzw. besser gar nicht, sondern nur die Variable zuweisen.
Ich bin mir auch nicht sicher, ob der Report nicht automatisch ein Get auf den Salesheader macht, und damit die beiden Flags löscht.
Die einzige Lösung für dieses Thema wäre das Sichern der Flags vor dem Aufruf und das zurücksichern danach, wie es der Standard auch in CU80 tut, wenn der Rechnungsrabatt berechnet wird.

Ein Ablauf der der hier funktionieren könnte, wäre der der Aufruf der Auftragsbestätigung mit anschließendem COMMIT VOR dem setzen der Flags, was aber wahrscheinlich nicht mit dem Event gelöst werden kann.

Gruß Fiddi

Re: Workaround-Frage für Fehler: Alte Datensatzversion

20. März 2017 19:59

fiddi hat geschrieben:Die einzige Lösung für dieses Thema wäre das Sichern der Flags vor dem Aufruf und das zurücksichern danach


Ok, im Prinzip mache ich das ja dann mit dem oben beschriebenem TRANSFERFIELDS. Ich habe halt das Problem, dass ich den SalesHeader nicht bis zum Ende meiner Programmierung ByReference durchschleifen kann. Außerdem holt sich "Report.Saveas" sowieso den Datensatz erneut und macht ein Modify. Nach der Report.Saveas-Funktion sind somit Ship und Invoice wieder weg, dafür der Druckzähler + 1. Mit dem Transferfields mache ich dann diese Änderung rückgängig. Sollte ein Rollback folgen, dann sollte der Druckzähler trotzdem hochgegangen sein. Ich weiß nun bloß nicht so genau was passiert, wenn das gleiche Event an einer anderen Stelle mit Datesatznänderungen benutzt wird. Das müsste ich mal durchprüfen.

Ich werde mal deiner Info folgen und schauen wie es der Standard nach der Rechnungsrabattberechnung macht.