Autor Thema: [Dokumente] Das Arbeiten mit Haupt- und Antwort-Dokumenten  (Gelesen 31004 mal)

Offline TMC

  • Freund des Hauses!
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 3.660
  • Geschlecht: Männlich
  • meden agan
Autor(en):Mathias (TMC)
Stand:22.09.2005
Version:1.3
Notes-Versionen:5.x, 6.x, 7.x
Änderungen:Version     Datum      Geändert von    Grund
 1.3        22.03.2007       Axel           Fehlerbereinigung in Code unter Punkt 3.9


Inhalt

1. Begriffe
2. Grundsätzliches
3. Praxis
    3.1 Antwortdokument erstellen per Button
    3.2 Feldinhalte vom Hauptdokument im Antwortdokument anzeigen
    3.3 Feldwerte beim Anlegen eines Antwortdokuments vom Hauptdokument übernehmen
    3.4 Felder in allen Antwortdokumenten aktualisieren, sobald sich diese im Hauptdokument ändern
    3.5 Dokumentlink zum Hauptdokument im Antwortdokument anzeigen lassen
    3.6 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen (1)
    3.7 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen per Button
    3.8 Eine einzige Maske für Haupt- und Antwort-Dokumente
    3.9 Löschen von Haupt- und Antwort-Dokumenten
4. Anregungen, Ergänzungen, Verbesserungsvorschläge


1. Begriffe


Hauptdokument      auch:    Elterndokument, Mutterdokument, Parent document, Main document

Antwortdokument   auch:   Tochterdokument, Unterdokument, Response document


2. Grundsätzliches


Sobald zu ein Hauptdokument per Formelsprache oder Lotus Script ein Antwortdokument erstellt wird, legt Lotus Notes nach dem ersten Speichern ein Feld $REF mit dem Datentyp „Response“ an. In dieses Feld wird beim Anlegen die ID des Hauptdokumentes geschrieben.


Hinweis: Das $REF – Feld ist erst nach dem ersten Speichern vorhanden.

Die Maske, die für Antwortdokumente verwendet werden soll, muss als solche ausgewiesen werden, in dem man den Typ auf "Response" stellt.



3. Praxis


3.1 Antwortdokument erstellen per Button

Man kann folgende Formel verwenden, die sowohl für eine Aktionsschaltfläche in einer Ansicht als auch in Masken geeignet ist.

Diese Formel ist geeignet, wenn es nur 1 Hierarchie von Antwortdokumenten geben soll.
Code
@If(Form = "";
   @Return(@Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) +  "um ein Antwortdokument zu erstellen."));
   @Success
);

@If(@IsResponseDoc;
   @Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) +  "um ein Antwortdokument zu erstellen.");
   @Command([Compose]; "RESPONSE MASKE")
)

Wenn mehrere Hierarchien möglich sein sollen, kann man folgende Formel verwenden:
Code
@If(Form = "";
   @Return(@Prompt( [OK];@DbTitle; "Bitte wählen Sie ein Hauptdokument aus" + @Char(13) +  "um ein Antwortdokument zu erstellen."));
   @Success
);

@Command([Compose]; "RESPONSE MASKE")



3.2 Feldinhalte vom Hauptdokument im Antwortdokument anzeigen

Dazu erstellt man im Antwortdokument ein berechnetes Textfeld und setzt in die Feldformel folgende @Formel:
Code
@If(@IsNewDoc;"";@GetDocField($REF;"FELD"))



3.3 Feldwerte beim Anlegen eines Antwortdokuments vom Hauptdokument übernehmen

Dazu setzt man in den Maskeneigenschaften der Antwortmaske folgenden Schalter:


In den Feldformeln der Antwortmaske, in die Werte vom Hauptdokument übernommen werden sollen, schreibt man den entsprechenden Feldnamen des Hauptdokuments


Im Beispiel ist „Parentdoc_Test“ der Feldname des Hauptdokumentes.



3.4 Felder in allen Antwortdokumenten aktualisieren, sobald sich diese im Hauptdokument ändern

Wenn Änderungen im Hauptdokument auf alle Antwortdokumente übertragen werden sollen, kann man dies über den Query Save – Event in der Hauptdokument-Maske steuern.

Hilfreich sind hierbei „Responses property“ und „StampAll method“  in der „NotesDocumentCollection“.


Beispiel:

Code
Sub Querysave(Source As Notesuidocument, Continue As Variant)
'------------------------------------------------------------------------------------------------------------------   
'Zweck: Feldwerte werden beim Speichern in alle Antwort-Dokumente übernommen   
'------------------------------------------------------------------------------------------------------------------   
   Dim session As New NotesSession
   Dim db As NotesDatabase
   Dim dc As NotesDocumentCollection
   Dim doc As NotesDocument
   Set db = session.CurrentDatabase
   
   If Source.IsNewDoc Then Exit Sub 'Wenn UIDoc neu ist dann verlasse Script
   
   Set doc = Source.Document 'UIDoc zu Backend-doc
   
   
   'alle Antwortdocs des Backend-Docs werden in die Collection aufgenommen
   Set dc = doc.Responses
   
   'Setze alle Felder der Collection, gespeichert wird automatisch   
   Call dc.StampAll( "Re_Feld1" , doc.Feld1(0) )
   Call dc.StampAll( "Re_Feld2" , doc.Feld2(0) )
   Call dc.StampAll( "Re_Feld3" , doc.Feld3(0) )
   
End Sub

Dieses Script kann man - etwas angepasst - auch in einem Agenten verwenden, der beispielsweise täglich alle Antwortdokumente aktualisiert.



3.5 Dokumentlink zum Hauptdokument im Antwortdokument anzeigen lassen

Um ein Dokumentlink-Symbol im Antwortdokument erscheinen zu lassen, welches auf das Hauptdokument verweist, erstellt man ein berechnetes Textfeld. In die Feldformel schreibt man $REF.




3.6 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen (1)

Prinzipiell ist dies z.B. mit folgendem Script möglich:

Code
Dim docParent As NotesDocument
Set docParent = db.getDocumentByUNID("UNID-String")   
Call doc.RemoveItem("$Ref")
Call doc.MakeResponse( docParent )


3.7 Einem Antwort-Dokument ein anderes Hauptdokument zuweisen per Button

Angenommen, man möchte es dem User per Aktionsbutton ermöglichen, dem aktuell geöffneten Antwortdokument ein neues Hauptdokument zuzuordnen, kann man wie folgt vorgehen:

Als erstes erstellt man eine Ansicht, die nur die Hauptdokumente enthält. Beispielsweise trägt man dazu in die View Selection SELECT FORM = "MyParentForm“ oder etwa SELECT $REF = "" ein.

Im Beispiel nenne ich die View ($Lookup_AssigningOtherParent).

In der View erstellt man mehrere Spalten, z.B.


Dabei lässt man in der letzten Spalte die DocumentUniqueID anzeigen. Hier im Beispiel soll beim Ändern des Hauptdokumentes auch der Titel übernommen werden, daher steht in der 3. Spalte:
Code
SubjectParent + "~" + @Text(@DocumentUniqueID)
Diese 3. Spalte sollte man verbergen. Das "~" ist ein Trennzeichen (Delimiter), es empfiehlt sich ggf., ein längeres String zu verwenden, z.B. "#'~+*'#".

Nun erstellt man in der Antwortmaske einen neuen Button und fügt folgendes Script ein:


Code
Sub Click(Source As Button)
	Const ITEMNAME_TITLE_OF_PARENT$ = "SubjectParent"
	Const VIEWNAME_LOOKUP_PARENT$ = "($Lookup_AssigningOtherParent)"
	Const DELIMITER_TITLE_UNID$ = "~"
	Const COLUMN_NO_LOOKUP$ = "3"		'which column contains the subject + delimiter + UNID ?
	Const MSGPICKLIST_TITLE$ = "Document selection"
	Const MSGPICKLIST_TEXT$ = "Please select a main document to which you want to assign this response document:"
	Const ERRMSG_1001$ = "Current document is not a response."
	Const ERRMSG_1002$ = "Current document is not in edit mode."
	Const ERRMSG_LINE2$ = "Operation has been canceled."
	
	On Error Goto ErrorHandler
	
	Dim session As New NotesSession
	Dim uiws As New NotesUIWorkspace
	Dim uidoc As NotesUIDocument
	Dim db As NotesDatabase
	Dim docCur As NotesDocument
	Dim docParent As NotesDocument	
	Dim vPicklistReturn As Variant
	Dim strLeftValue As String   
	Dim strRightValue As String
	Dim i As Integer
	
	Set db = session.CurrentDatabase
	Set uidoc = uiws.CurrentDocument
	Set docCur = uidoc.Document
	
	'Only continue if the current document is a response & if it is in the edit mode
	If Not docCur.IsResponse Then Error 1001, ERRMSG_1001
	If Not uidoc.EditMode Then Error 1002, ERRMSG_1002
	
	'Display the main documents and let the user select one
	vPicklistReturn =uiws.Pickliststrings(PICKLIST_CUSTOM,  False, db.Server, db.FilePath,VIEWNAME_LOOKUP_PARENT,_
	MSGPICKLIST_TITLE, MSGPICKLIST_TEXT, COLUMN_NO_LOOKUP)
	
	If Isempty(vPicklistReturn) Then Goto GoOut	'user did not select a document
	
	'Get left and right value
	strLeftValue = Strleft(vPicklistReturn(0), DELIMITER_TITLE_UNID)
	strRightValue = Strright(vPicklistReturn(0), DELIMITER_TITLE_UNID)
	
	'Set subject of main document to an item of the current response document	
	Call docCur.ReplaceItemValue(ITEMNAME_TITLE_OF_PARENT, strLeftValue)	
	
	'Assign the new main document to the current response doczment
	Set docParent = db.getDocumentByUNID(strRightValue)   
	Call docCur.RemoveItem("$Ref")
	Call docCur.MakeResponse( docParent )
	
	'Refresh
	Call uidoc.Reload
	Call uidoc.Refresh
	
GoOut:
	Exit Sub
ErrorHandler:
	Select Case Err
	Case 1001 To 1999: 'User defined errors
		Msgbox Error$ & Chr(10) & Chr(10) & ERRMSG_LINE2, 64, db.Title
		Resume GoOut
	Case Else:
		ErrorMsg ' Your error sub. See this AtNotes thread for further information: http://www.atnotes.de/index.php?topic=11980.0
		Resume GoOut
	End Select
End Sub


Als Ergebnis sieht der Anwender folgendes Fenster, wenn er auf den Button klickt:


Nach Auswahl und Bestätigung mit "OK" wird dem Antwortdokument das neu ausgewählte Hauptdokument zugeordnet.


3.8 Eine einzige Maske für Haupt- und Antwort-Dokumente

Grundsätzlich wird von Notes vorausgesetzt, dass es separate Masken für Haupt- und Antwort-Dokumente gibt. Dabei ist in der Antwortmaske unter Type "Response" oder "Response to Response" zu setzen (siehe -> Kap. 2. Grundsätzliches).

Es gibt aber die Möglichkeit, Haupt- und Antwortdokumente auf Basis einer einzigen Maske zu erstellen. Dies kann von Vorteil sein, z.B. wenn sich die Haupt- und Antwortmaske kaum unterscheiden und man mit Hide/When-Formeln (siehe auch: AtNotes BP: Verbergen-Wenn (Hide-When) - Formeln) die jeweils zu verbergenden Absätze definiert.

Bedingungen:
  • Neue Antwort-Dokumente können nicht per Formelsprache erstellt werden, sondern nur per LotusScript, da hierzu die MakeResponse - Methode der NotesDocument-Klasse notwendig ist.
  • Zusätzlich ist es bei der Erstellung notwendig, die Versionskontrolle zu aktivieren (Item $VersionOpt setzen), sonst funktioniert die MakeResponse - Methode der NotesDocument-Klasse nicht bei neuen Dokumenten, wenn man diese im Backend erzeugt und dann im Frontend anzeigen lässt (um den Compose - @Command nachzubilden). Details zur Versionskontrolle und $VersionOpt: siehe Designerhilfe.

Beispiel für das Erstellen eines neuen Antwort-Dokumentes per Lotus Script:

Das folgende Script ist für einen Button gedacht und kann in Ansichts- und Masken-Buttons eingesetzt werden. Falls das Script mehrfach verwendet wird, sollte man dieses in einem Agenten, einer 'Shared Action' oder in einer ScriptLibrary hinterlegen.

Das neu erstellte Dokument wird dabei nicht gespeichert (NotesUIDocument.IsNewDoc gibt True zurück), d.h. das Verhalten ist prinzipiell wie beim Compose - @Command.

Code
Sub Click(Source As Button)
	
	'Constants for this procedure
	Const FORMNAME_RESPONSE$ = "frmTest"
	Const ERR_NODOCSEL_TITLE$ = "Error: No document selected"
	Const ERR_NODOCSEL_MSG$ = "You need to select a document to create a response document of it."
	
	On Error Goto ErrorHandler					'Of course we trap errors
	
	'The dim section
	Dim uiws As New NotesUIWorkspace
	Dim uidocNew As NotesUIDocument
	Dim session As New NotesSession
	Dim db As NotesDatabase
	Dim docSel As NotesDocument
	Dim docNew As NotesDocument
	
	'We need the current database
	Set db = session.CurrentDatabase
	
	'Get current document as NotesDocument object
	If Not uiws.CurrentDocument Is Nothing Then
		Set docSel = uiws.CurrentDocument.Document	'Document opened in form
	Elseif Not session.DocumentContext Is Nothing Then
		Set docSel = session.DocumentContext			'Document selected in view
	End If
	If docSel Is Nothing Then						'User did not select a document
		Msgbox ERR_NODOCSEL_MSG, 48, ERR_NODOCSEL_TITLE
		Goto GoOut
	End If
	
	'Create new backend response document
	Set docNew = db.CreateDocument
	Call docNew.ReplaceItemValue("Form", FORMNAME_RESPONSE)
	Call docNew.MakeResponse(docSel)

	'This is necessary since we use one form for both main and response documents
	Call docNew.ReplaceItemValue("$VersionOpt","1")
	
	'Finally, open new document in the frontend
	Call uiws.EditDocument(True, docNew)
	
	
GoOut:
	Exit Sub
ErrorHandler:
	ErrorMsg  ' Your error sub. See this AtNotes thread for further information: http://www.atnotes.de/index.php?topic=11980.0
	Resume GoOut
End Sub


3.9 Löschen von Haupt- und Antwort-Dokumenten

Grundsätzlich werden beim Löschen von Hauptdokumenten die Antwort-Dokumente nicht mitgelöscht. Damit auch die Antwortdokumente gelöscht werden, kann man folgendes Lotus Script einsetzen. Es werden dabei rekursiv alle Antwortdokumente abgearbeitet und gelöscht.

1. Im PostDocumentDelete - Event des Database-Scriptes folgenden Code einsetzen:
Code
Dim doc As NotesDocument
Dim collection As NotesDocumentCollection
Set collection = Source.Documents

If collection.Count > 0 Then
	For i = 1 To collection.Count
		Set doc = collection.GetNthDocument(i)
		Call DeleteResponseDocs(doc)
		Call doc.Remove(True)
	Next  'For i = 1 To collection.Count
End If  'If collection.Count = 0 Then

2. Folgende (rekursive) Sub hinzufügen:
Code
Sub DeleteResponseDocs (doc As NotesDocument)
	
	'This is a recursive sub to access all the descendants of a particular document. 
	
	Dim collResponses As NotesDocumentCollection
	Dim docTemp As NotesDocument
	Dim docDummy As NotesDocument
	
	Set collResponses = doc.Responses
	Set docDummy= collResponses.GetFirstDocument
	While Not (docDummy Is Nothing)
		Set docTemp = collResponses.GetNextDocument(docDummy)
		Call DeleteResponseDocs(docDummy)	'The recursive call
		Call docDummy.Remove(True)
		Set docDummy = docTemp
	Wend  'While Not (docDummy Is Nothing)
	
End Sub





4. Anregungen, Ergänzungen, Verbesserungsvorschläge


Anregungen, Ergänzungen und Verbesserungsvorschläge bitte im Best Practices Diskussionsforum posten.

Insbesonders wären weitere Fragestellungen interessant, die immer wieder vorkommen und auch hier beschrieben werden sollten.


« Letzte Änderung: 22.03.07 - 21:05:44 von Axel »
Matthias

A good programmer is someone who looks both ways before crossing a one-way street.


 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz