Das Notes Forum
Domino 9 und frühere Versionen => ND8: Entwicklung => Thema gestartet von: smokyly am 10.01.12 - 09:44:09
-
Guten Morgen.
Wir haben eine Anwendung zugekauft, in der wir Dokumente erstellt haben. In der Maske wird eine versteckte Teilmaske eingebunden und hier wird im Postsave geprüft, ob sich ein bestimmtes Feld geändert hat. Trifft dies zu, wird eine Mail versendet, die einer Mail-IN mitteilt, dass sich was geändert hat.
Jetzt muss in vielen Dokumenten dieses Feld nach einem bestimmten Kriterium geändert werden.
Ich dachte mir, ich schreibe einen Agenten (Formel, nicht Skript)), der zwei Dialogfelder hat "alter Wert" "neuer Wert" und sich dann die Dokumente sucht und den Wert des Items austauscht.
Irre ich mich, wenn ich mir denke, dass dabei aber diese Änderungsmail nicht versendet wird?
Wenn nein, was müsste ich machen, damit die Mail doch versendet wird? Ich brauche keinen Code, sondern nur eine formale Beschreibung der Vorgehensweise.
Vielen Dank schon mal.
Gruss
-
Guten Morgen
Wenn Du das Dokument im Backend (per Agent) änderst, wird der Postsave nicht ausgeführt. Daher wird kein Mail verschickt.
Ist das Mail zwingend nötig? Dann würde ich den entsprechenden Code aus dem Postsave Event in deinen Agenten einfügen oder die Meldung in deinem Agenten generieren.
Gruss
-
Hallo und Danke!
Wenn Du das Dokument im Backend (per Agent) änderst, wird der Postsave nicht ausgeführt. Daher wird kein Mail verschickt.
Gut, dann hatte ich das schon richtig verstanden.
Ist das Mail zwingend nötig?
Ja, absolut. Die Mail ist für die Buchhaltung, dass sich der Inventarstandort (=Kostenstelle) geändert hat und in der Anlagenbuchhaltung eine Umbuchung vorzunehmen ist.
Dann würde ich den entsprechenden Code aus dem Postsave Event in deinen Agenten einfügen oder die Meldung in deinem Agenten generieren.
Dann muss ich aber statt Formel Script verwenden, der Code ist Script. Da bin ich nun gar nicht fit.
Hmm, Moment, ich könnte doch diesen Code in einen Agenten eintragen, welcher durch "Auswahl in der Agentenliste" von meinem Formelagenten aufgerufen wird?!
-
Dazu müsstest Du aber das gerade bearbeitete Dokument an den Agent übergeben. Trivial wird das nicht, wenn man nicht in LS fit ist.
Bernhard
-
Hallo Bernhard,
da hab ich mir auch eben die Zähne ausgebissen.
Den Code als Sub in einer Scriptbibliothek ablegen und dann per Formel aufrufen geht ja auch nicht, so wie ich das sehe. Zumindest finde ich in der Formelübersicht keinen entsprechenden Aufruf...
Per Formel Dokument öffnen, Feld verändern und dann speichern scheitert am Speichern. :'(
Ich glaube, ich mach das dann doch komplett in Script. Hab ja hier ein sehr dickes Buch liegen...
Danke nochmal und beste Grüsse.
-
Nun denn - der Benutzer markiert sich in der Ansicht die gewünschten Dokumente oder sucht sich diese über Volltext.
Der Agent läuft auf "Alle ausgewählten Dokumente" und führt folgendes Script aus:
Sub Initialize
Dim ws As New NotesUIWorkspace
Dim session As New NotesSession
Dim db As NotesDatabase
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
Dim uidoc As NotesUIDocument
Dim Kostenstelle_neu As String
Set db := session.CurrentDatabase
Set dc := db.UnprocessedDocuments
Set doc := dc.GetFirstDocument
Kostenstelle_neu := (InputBox$("Bitte neue Kostenstelle angeben!"))
While Not doc Is Nothing
Set uidoc := ws.EditDocument(True, doc)
Call uidoc.FieldSetText(Kostenstelle, Kostenstelle_neu )
Call uidoc.Refresh
Call uidoc.Save
Call uidoc.Close
Set doc := dc.GetNextDocument(doc)
Wend
End Sub
Würde das tun? Im Moment ist mein Testsystem in Wartung, kann es also nicht ausprobieren.
Grüsse
-
":=" ist falsch, in LS ist das "=".
Weiters: Warum machst Du das im Frontend? Du kannst doch gleich im Backend Deinen Wert setzen:
While Not doc Is Nothing
doc.Kostenstelle = Kostenstelle_neu
Call doc.Save (True, False, True)
Set doc = dc.GetNextDocument(doc)
Wend
Bernhard
-
":=" ist falsch, in LS ist das "=".
Schande, zu viel PL/SQL im Kopf. :-X
doc.Kostenstelle = Kostenstelle_neu
Ja, da hab ich zu kompliziert gedacht.
Weiters: Warum machst Du das im Frontend? Du kannst doch gleich im Backend Deinen Wert setzen:
Ich dachte, dann zieht doch das andere Script aus dem Postsave der Teilmaske nicht? ???
-
Den entsprechenden Code bzw. die Aufrufe zu fertigen Routinen kannst Du doch in Deinem Agentileinchen auch einsetzen, Geri.
Bernhard
-
Den entsprechenden Code bzw. die Aufrufe zu fertigen Routinen kannst Du doch in Deinem Agentileinchen auch einsetzen, Geri.
Bernhard
;D
Du traust mir nun wahrlich zu viel zu. Das Büchlein, aus dem ich mir den Code zusammengesucht habe, hat nur über 1200 Seiten. Bis ich mir daraus dann zusammengesaugt habe, was das andere Script genau macht und es angepasst habe, werden wohl einige Sekunden vergehen...
Und der andere Code ist nicht in einer Bibliothek abgelegt, sondern direkt im Postsave (bzw. im Postopen wird sich da auch was gemerkt / zusammengebastelt).
Aber Du hast schon wahr! :)
Grundsätzlich würde mein Agent aber laufen?!
Edit: Wenn ich drüber nachdenke - ich habe die Befürchtung, dass das lange laufen wird und ein ziemliches Geflacker auf dem Bildschirm werden wird. :-[
Ich versuch mal, ob ich die Scripte zusammen führen kann. Darf ich dann zur Überprüfung das Ding nochmal hier rein stellen?
Danke erstmal.
-
Mein Vorschlag für das Backend würde aber nicht "flackern". Flott ist das auch.
Wie wird denn bzgl. was im PostSave aufgerufen?
Bernhard
-
Das Verfahren über das Frontend hat neben dem Flackern auch noch einen weiteren Nachteil: Probier das mal mit mehreren Dokumenten aus. Spätestens beim 50. oder 60. Dokument raucht Dir nämlich der Client ab (ich habe solch eine Routine, die über das Frontend MUSS, das geht da leider nicht anders, dort haben wir eine Grenze von 40 eingestellt).
-
Mein Vorschlag für das Backend würde aber nicht "flackern". Flott ist das auch.
Ja, das hatte ich verstanden, drum mein Umschwenken.
Wie wird denn bzgl. was im PostSave aufgerufen?
Bernhard
Es wird eine Mail erstellt, durch einen Vergleich des aktuellen Wertes eines Items des Dokuments und einer Variablen(!, also kein Feld), die woher auch immer kommt und dann wird da noch was mit Workflow gesteuert und gemacht, aber da steig ich nicht durch, da dann Bibliotheken aufgerufen werden. Das mit der Mail war ne Schnellanpassung für uns, der Rest ist Standard des Herstellers.
So wie ich das sehe, zieht bei einer Änderung des Feldes im Dialog nur die Mailgeschichte, ganz sicher bin ich natürlich nicht.
Jetzt raucht die Birne...
-
... und einer Variablen(!, also kein Feld), die woher auch immer kommt ...
Die Variable ist bestimmt in den Declarations deklariert und wird im PostOpen gesetzt.
Das ist ein gängiges und gutes Verfahren:
Globale Variable im PostOpen mit dem aktuellen Feldwert setzen
Im PostSave (oder QuerySave) den nun aktuellen Feldwert mit der Variablen (also dem Wert zum Zeitpunkt des Öffnens) vergleichen und daraus Aktionen ableiten
-
Das Verfahren über das Frontend hat neben dem Flackern auch noch einen weiteren Nachteil: Probier das mal mit mehreren Dokumenten aus. Spätestens beim 50. oder 60. Dokument raucht Dir nämlich der Client ab (ich habe solch eine Routine, die über das Frontend MUSS, das geht da leider nicht anders, dort haben wir eine Grenze von 40 eingestellt).
Danke für die Info. Gut zu wissen.
-
Die Variable ist bestimmt in den Declarations deklariert
Da hatte ich zuerst gesucht.
und wird im PostOpen gesetzt.
Super, gefunden, hier deklariert und gesetzt.
Das ist ein gängiges und gutes Verfahren:
Globale Variable im PostOpen mit dem aktuellen Feldwert setzen
Im PostSave (oder QuerySave) den nun aktuellen Feldwert mit der Variablen (also dem Wert zum Zeitpunkt des Öffnens) vergleichen und daraus Aktionen ableiten
OK, und nun hab ich auch schon die Idee, wie ich das dann im Backendscript umsetze.
Beste Grüsse!
-
und wird im PostOpen gesetzt.
Super, gefunden, hier deklariert und gesetzt.
Wenn die Variable im PostOpen deklariert ist, kann sie nicht im PostSave zur Verfügung stehen. Sie muss in den Declarations der Maske oder den Declarations von Globals deklariert sein. Falls die gleiche Variable nochmal im PostOpen deklariert ist, gelangen die Daten nicht in die global deklarierte Variable, und der Inhalt ist wiederum nicht im PostSave verfügbar.
Sorry für meine Pingeligkeit, aber das ist für die Funktionsweise sehr wichtig.
-
Hallo Peter, das ist eine Teilmaske, da steht in den Deklarationen nichst drin. Im Postopen finde ich das:
Kostenstelle = source.Document.Kostenstelle(0)
Also ist das keine implizite Deklaration mit Wertsetzen, sondern nur eine Zuweisung?
Hat natürlich für mein Anliegen nicht wirklich was zu tun, ist Interesse.
-
Also so sieht der Code für den Agenten im Initalize aus:
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
Dim Kostenstelle_neu As String
Dim Kostenstelle_alt As String
Set db = session.CurrentDatabase
Set dc = db.UnprocessedDocuments
Set doc = dc.GetFirstDocument
Kostenstelle_neu = (InputBox$("Bitte neue Kostenstelle angeben!"))
While Not doc Is Nothing
Kostenstelle_alt=doc.Kostenstelle
doc.Kostenstelle = Kostenstelle_neu
Call doc.Save(True,False,True)
Call sendmail(doc,Kostenstelle_alt)
Set doc = dc.GetNextDocument(doc)
Wend
End Sub
Dann habe ich noch eine Sub "sendmail" gebastelt, die das Mail erstellt und noch die anderen benötigten Funktionen / Subs aus der Teilmaske in den Agenten geschoben. In den Options hab ich mit Use eine benötigte Bibliothek angegeben.
Konnte den Agenten ohne Fehler speichern.
A-Bär: Das verstehe ich noch nicht ganz - das sendmail hat ja zwei Übergabeparameter:
Sub Sendmail(Source As NotesDocument, P_Kostenstelle_agent As String)
Muss ich Source und P_Kostenstelle_agent denn nun nochmal in den Declarations aufnehmen, oder sind diese denn nun implizit definiert? Ich behaupte mal Letzteres, da es in anderen Sprachen auch so ist.
-
Das ist schon korrekt so, Geri. Subs / Functions deklarieren ihre Parameter implizit.
Bernhard
-
Ich fühl mich jetzt gar nicht mehr so doof! ;D
So, dann geh ich das mal produktiv "testen". Man möge mir die Daumen drücken.
Danke an alle, die mir bisher geholfen haben. Heute hab ich doch sehr viel von der Konstruktion LS verstehen lernen können. Da kommt kein Buch hin...
-
Warum testest Du das nicht erstmal in einer SpielDB (wenn Deine Testumgebung noch down ist)? Leere Kopie Deiner DB (oder komplette, however), zwei Dokumente markieren und nachschauen, was passiert.
Bernhard
PS: Tipp, weil ja immer etwas schief gehen kann. Füge in Deinen Code gleich ein ErrorHandling ein, mindestens sowas simples hier:
Nach den Declarations in Deiner Sub:
On Error Goto ErrorRoutine
Vor End Sub setzt Du noch ein Exit Sub und anschliessend (immer noch vor End Sub)
ErrorRoutine:
Messagebox Error$ & " (" & Cstr (Err) & ") in line " & Cstr (Erl)
Wenn es mal scheppert, wirst Du diesen drei Zeilen sehr dankbar sein ;-)
-
Warum testest Du das nicht erstmal in einer SpielDB (wenn Deine Testumgebung noch down ist)? Leere Kopie Deiner DB (oder komplette, however), zwei Dokumente markieren und nachschauen, was passiert.
Geht nicht. Da hat der Hersteller sein Finger mit Lizenzschlüsseln drauf, die Replik-ID abhängig sind und weiß der Teufel noch prüft. Lokal ist auch nicht. Die Testumgebung hat der Hersteller eingerichtet (der Hinweis, nur, damit sich keiner wundert).
PS: Tipp, weil ja immer etwas schief gehen kann. Füge in Deinen Code gleich ein ErrorHandling ein, mindestens sowas simples hier:
Nach den Declarations in Deiner Sub:
On Error Goto ErrorRoutine
Vor End Sub setzt Du noch ein Exit Sub und anschliessend (immer noch vor End Sub)
ErrorRoutine:
Messagebox Error$ & " (" & Cstr (Err) & ") in line " & Cstr (Erl)
Danke für den Hinweis, bzw. Code, das hatte ich nicht mehr auf dem Schirm. Das sieht ja fast wie in "meiner" Programmiersprache aus.
Wenn es mal scheppert, wirst Du diesen drei Zeilen sehr dankbar sein ;-)
Absolut, das wissen sogar meine Kollegen zu schätzen, wenn ich mal nicht da bin und meine anderen Programme raus fliegen. ;D
-
Geht nicht. Da hat der Hersteller sein Finger mit Lizenzschlüsseln drauf, die Replik-ID abhängig ...
Herrjeh, wer macht denn sowas? Die Einhaltung von Lizenzbestimmungen lassen sich nun wirklich anders anders und adminfreundlicher handhaben.
Wenn es Dir diese Replik mal zerhaut, dann kannst Du ja nicht mal mehr einen Reparaturversuch mittels einer Kopie probieren. Und Archiv-DBs sind so auch nicht machbar.
Aber egal - das hat mit diesem Thread ja nichts zu tun.
Bernhard
-
Herrjeh, wer macht denn sowas?
Die Firma kennst Du ganz sicher vom Namen her. ;)
Wenn es Dir diese Replik mal zerhaut, dann kannst Du ja nicht mal mehr einen Reparaturversuch mittels einer Kopie probieren.
Wenn der Verhau nicht gerade im Cluster repliziert wird - sonst bleibt nur Rücksicherung.
Zurück zum Thema:
Das Errohandling hat angeschlagen.
Type mismatch (13) in Line...
Und zwar in dieser Zeile:
Kostenstelle_alt=doc.Kostenstelle
Sehe ich mir das Item über die Eigenschaften an, ist das Text. Im Debugger sagt man mir bei dem Item als Type 1280 / Long. Wo liegt mein Denkfehler?
-
Items sind immer (ausser RTIs) immer Arrays! Daher musst Du (in diesem Fall, da Du einen skalaren Wert erhalten möchtest) wie folgt notieren:
Kostenstelle_alt=doc.Kostenstelle (0)
Bernhard
-
Items sind immer (ausser RTIs) immer Arrays! Daher musst Du (in diesem Fall, da Du einen skalaren Wert erhalten möchtest) wie folgt notieren:
Kostenstelle_alt=doc.Kostenstelle (0)
Bernhard
Bernhard, ich hoffe, Du schickst mir nicht irgendwann ne gepfefferte Rechnung in Form von "Jetzt lies endlich das Buch durch!" :-X.
Vielen Dank für die Info.
Ich war schon im Buch vertieft und hatte mit "Dim blabla Liste as String" probiert, hat dann aber auch nicht funktioniert.
Die Änderung wurde gemacht, das Mail aber nicht versendet, weil da auch ein Type Mismatch kommt.
Sub Sendmail(Source As NotesDocument, P_Kostenstelle_agent As String)
...
Dim oDoc As NotesDocument
...
Set oDoc = Source.Document--> da kracht es
Das ist aber nicht mein Code, sondern aus der funktionierenden Teilmaske. Einzig die Sub-Definition habe ich geändert. Original ist das hier:
Sub Postsave(Source As Notesuidocument)
Wieso spielt das da eine Rolle, ob das Quelldokument aus dem Back- bzw. Frontend kommt?
-
Hallo Geri,
wenn Ihr mal bezahlbare / bezahlte Unterstützung braucht: Immer gerne. Du hast ja meine Mailadresse ;)
Zu Deinem Problem:
NotesDocument und NotesUIDocument sind durchaus sehr unterschiedliche Dinge. Simpel gesprochen: Das eine liegt auf der Platte, das andere lümmelt sich in Deinem Speicher und auf dem Bildschirm.
Wenn also SendMail ein NotesDocument erwartet (was sinnhaft ist) und PostSave Dir ein NotesDocument als Source liefert, dann musst Du den Backend-Teil vom NotesUIDocument an SendMail übergeben, also
Source.Document
Sehr sinnhaft ist es aber nicht, in SendMail den Parameter vom Typ NotesDocument als "Source" zu bezeichnen, da in allen Events, die Notes so mitliefert und die sich auf Dokumente beziehen, diese jeweils NotesUIDocuments sind. Aber das ist ja nicht Deine Party.
Was ich aber gerade beim genaueren Lesen fragend feststelle: Dein Zitat aus dem Code von SendMail ist das Original vom Hersteller? Das würde aber niemals funktieren, da Source As NotesDocument keine property Document hat!
HTH,
Bernhard
-
Hallo Geri,
wenn Ihr mal bezahlbare / bezahlte Unterstützung braucht: Immer gerne. Du hast ja meine Mailadresse ;)
Sobald ich ein Projekt habe, welches sich für eine Schulung eignet, melde ich mich selbstverständlich.
Das hier ist nur ne Übungsaufgabe, bzw. ich will dem Benutzer einen Gefallen tun.
Zu Deinem Problem:
NotesDocument und NotesUIDocument sind durchaus sehr unterschiedliche Dinge. Simpel gesprochen: Das eine liegt auf der Platte, das andere lümmelt sich in Deinem Speicher und auf dem Bildschirm.
Soweit war mir das bekannt. Danke für die Bestätigung.
Wenn also SendMail ein NotesDocument erwartet (was sinnhaft ist) und PostSave Dir ein NotesDocument als Source liefert, dann musst Du den Backend-Teil vom NotesUIDocument an SendMail übergeben, also
Source.Document
Sehr sinnhaft ist es aber nicht, in SendMail den Parameter vom Typ NotesDocument als "Source" zu bezeichnen, da in allen Events, die Notes so mitliefert und die sich auf Dokumente beziehen, diese jeweils NotesUIDocuments sind. Aber das ist ja nicht Deine Party.
HTH,
Bernhard
Äh, das hab ich nun nicht wirklich verstanden. Aber ich glaube, da liegt auch ein Mißverständnis vor.
Ich habe mir aus dem Postsave den Code für den Mailversand heraus gesucht, als meine Sub "Sendmail" gespeichert und halt statt "Source as NotesUIDocument" "Source as NotesDocument" in meiner Sub geändert. Ansonsten ist an dem Code für den Mailversand nichts hinzugefügt, sondern nur überflüssiges heraus genommen (die WF-Geschichte).
Das Sub "PostSave" kommt im Agenten nicht vor.
Was ich aber gerade beim genaueren Lesen fragend feststelle: Dein Zitat aus dem Code von SendMail ist das Original vom Hersteller? Das würde aber niemals funktieren, da Source As NotesDocument keine property Document hat!
Nein, ebend nicht vom Hersteller, sondern auf meinem Mist gewachsen. :P
Aber jetzt hat es Klick gemacht!
Super! Es funktioniert!
Ich falle mal kurz auf die Knie und sende Dir ein "Ich bin unwürdig! Ich bin unwürdig!" :knuddel:
Danke nochmals vielmals! Solltest Du mal Ärger mit PL/SQL haben... ;)
-
Sobald ich ein Projekt habe, welches sich für eine Schulung eignet, melde ich mich selbstverständlich.
...
Super! Es funktioniert!
Ich falle mal kurz auf die Knie und sende Dir ein "Ich bin unwürdig! Ich bin unwürdig!" :knuddel:
Danke nochmals vielmals! Solltest Du mal Ärger mit PL/SQL haben... ;)
Hallo Geri,
da kann ich jetzt in Punkten antworten:
1. Ich mache *auch* Schulungen, bin aber in erster Linie Entwickler für schwierige Fälle. Wenn Ihr also mal "Zeit ist Geld" sparen wollt ... Trainings on the job natürlich auch immer gerne!
2. Du musst nicht auf die Knie fallen! Und Du bist nicht "unwürdig", sondern Du startest gerade etwas Neues und bist zwangsläufig "Newbee". Und das waren wir *alle* (!!!) mal!
3. Das ist notiert. Ich komme darauf gerne zurück!
Beste Grüsse,
Bernhard
-
Eines noch:
Soweit ich das sehe, kann ich im Script nicht abfangen, ob der Benutzer auf "Abbrechen" in der InputBox geklickt hat?!
Dann wäre meine Idee, einen seltsamen Default mit zu geben und wenn dann dafür Empty zurück kommt, oder der Default (bei OK ohne Eingabe), breche ich die Verarbeitung ab.
Den Abbruch der Verarbeitung bekommt man doch sicher sauberer hin, als die Schleife durch ein goto zu verlassen, oder? O0 Käse...
Schönen Abend noch!
-
Inputbox$ ist eine "Simpel-Dialog ". Abbrechen geht da nicht (andere Speachen - nicht nur VB - bieten ja auch ähnlich einfache Konstrukte für "wenn es mal schnell gehen muss". Logischerweise trennt man sich von sowas mit zunehmender Erfahrung (wieviele zigtausend Programmzeilen sind von mir derzeit von Bukarest bis Karup, von Iwaki bis Georgia / U.S.A. derzeit im Einsatz? Nie gezählt ... Aber Inputbox kommt da nicht vor).
Du bist ja aber am Anfang, und mir scheint auch Dein Zweck derzeit dieses Mittel zu heiligen. Also: Ruhig angehen, bestimmte Kompromisse akzeptieren (aber nicht verinnerlichen), der Rest kommt!
Was Du erstmal machen kannst, um einen Abbruch zu ermöglichen:
- Return value von InputBox$ auf = "" abfragen
- Messagebox anschliessend als Function einsetzen ("Sie haben grzmcnfuh eingegeben? Soll dieser Wert wirklich übernommen werden?")
Wenn Du schon mal nach anderen Methoden Ausschau halten willst - beide gehören zur NotesUIWorkspace-Klasse:
- Prompt: Simple (wie in Formelsprache). Ein Abbruch wird hier signalisiert.
- Dialogbox: Da geht noch erheblich mehr, zum Beispiel Mehrfachabfragen. Das Erkennen des Abbruchs ist auch hier gegeben.
Bernhard
-
Danke Bernhard,
das Ding läuft jetzt fast perfekt, wobei ich erstmal mit InputBox und MsgBox gewerkelt habe. Einzig eine Eingabevalidierung auf existierende Kostenstellen fehlt, aber da komm ich so nicht ran, da hat sich der Hersteller ein eigenes Konstrukt geschaffen. Rein von der Funktion her tut das Ding schon mehr, als ich zu Anfang vor hatte.
Beste Grüsse