Monday, May 12, 2008

SnTT: Field-level LastModified during document save

My friend Cal was having some problems trying to figure out whether certain fields on a document were modified during a document save. Of course you could use the old trick of ripping through NotesDocument.Items in PostOpen, store the values, then compare the values on save with what the original values were. But Cal didn't need to know what changed, he just needed to know whether it changed. And so we went on a wild goose chase together.

The NotesItem class includes a LastModified property. But guess what: while the front end document is open it reports the same date as NotesDocument.LastModified, even if the field hasn't actually been changed. Notes holds the UI document open all the way through to PostSave, so there are no form events where the UI document is empty, which actually makes sense.

The solution is to make Notes think the document isn't open. Enter Delete. I've written about Delete a couple of times before; it removes an object from the Notes cache immediately. Combining this knowledge with some other techniques, we end up with the following


Sub Postsave(Source As Notesuidocument)
'Ignore new documents
If Source.IsNewDoc Then Exit Sub

Dim db As NotesDatabase
Dim session As New NotesSession
Dim doc As NotesDocument
Dim maildoc As NotesDocument
Dim tmpID As String

Set db = session.CurrentDatabase
tmpID = source.document.UniversalID

'Force the front end document to close
source.Close(True)

'Delete it from the cache
Delete source

'Reopen the backend document
Set doc = db.GetDocumentByUNID(tmpID)

' Checks for field(s) that have been modified and sends a notification.

Forall item In doc.Items
If (item.LastModified >= doc.LastModified) Then
Set maildoc = New NotesDocument( db )
maildoc.Form = "Memo"

' Person to be notified.
maildoc.SendTo = "<name>"
maildoc.Subject = "<subject>"
Set rtitem = New NotesRichTextItem( maildoc, "Body" )
Call rtitem.AppendText( "The iteration for """ + doc.Title(0) + """ was changed by " + session.UserName + "." )
Call rtitem.AddNewLine( 2 )
Call rtitem.AppendText( "Link to Document -> " )
Call rtitem.AppendDocLink( doc, db.Title )
Call maildoc.Send( False )
End If
End Forall
End Sub


This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.

4 comments:

  1. Perhaps you want to revisit the loop at the end - to avoid sending one email per changed item? ;-)

    ReplyDelete
  2. In this case there were a limited number of fields that could be changed so it wasn't an issue, but thanks for pointing it out. The plan is to eventually create a keyword doc with a list of fields to check, and to report them all at once.

    ReplyDelete
  3. Another trick:

    In the QuerySave do a lookup to the document using it's universal ID as the key in a view. (has to be NotesView.GetDocumentByKey - not NotesDatabase.GetDocumentByUNID). You can then do a field by field comparision to the ContextDocument.

    ReplyDelete
  4. FYI - the technique I mentioned will work on Web or Notes client.

    ReplyDelete