Avatar of scribla
scribla
Flag for United Kingdom of Great Britain and Northern Ireland asked on

Agent to update all documents in a view

I have implemented some LS provided by Bill Hanson https://www.experts-exchange.com/questions/23301283/View-formula-Attachment-names-only-possible-per-document-or-possible-per-field.html

I am now wondering how to get the LS to update the fields on the 8000+ docs already in the database, I've tried to do this with an agent but I can't seem to do it, is it at all possible?

If Bill is reading this, is it possible to put your PostSave code into a agent? I am hoping to perform this without editing and saving each document if possible?
Lotus IBM

Avatar of undefined
Last Comment
Bill-Hanson

8/22/2022 - Mon
Bill-Hanson

Sure.

The agent below will do the same thing to all documents in the "DocumentsToUpdate" view (you'll need to change the view name in the code below to the name of a view that contains your documents).

To create the agent...

1) From the designer, select New Agent.
2) Change the type to "LotusScript".
3) If you added the DocGetFileLocations to a script library, then add this line to the agent's "Options" module (replacing "common_functions" with the name of your library):

    Use "common_functions"

4) If you don't have a library, then paste all of the DocGetFileLocations code into the "Declarations" module.
5) Paste the code below into the "Declarations" module.
6) Set the agent's trigger to ""Action menu selection".
7) Set the agent's target to "None".
8) Save and run the agent.
Sub Initialize
	
	Dim sess As New NotesSession
	Dim db As NotesDatabase
	Dim view As NotesView
	Dim doc As NotesDocument
	Dim fileMap List As Variant
	Dim hasDoc As Boolean
	Dim hasXl As Boolean
	
	' Get the view that contains the documents to process
	Set db = sess.CurrentDatabase
	Set view = db.GetView("DocumentsToUpdate")
	Call view.Refresh
	If (view.AllEntries.Count = 0) Then Exit Sub
	
	' Loop through all documents in the view.
	Set doc = view.GetFirstDocument()
	Do While (Not doc Is Nothing)
		Call DocGetFileLocations(doc, fileMap)
		hasDoc = False
		hasXl = True
		If (Isempty(fileMap)) Then
			doc.FileDisplay = "4. No Attachments"
		Else
			Forall fileNames In fileMap
				Select Case Listtag(fileNames)
				Case "WordDocs"
					Forall fileName In fileNames
						If (Right(Lcase(fileName), 4) = ".doc") Then
							hasDoc = True
							Exit Forall
						End If
					End Forall
				Case "ExcelDocs"
					Forall fileName In fileNames
						If (Right(Lcase(fileName), 4) = ".xls") Then
							hasXl = True
							Exit Forall
						End If
					End Forall
				End Select
			End Forall
			If (hasDoc And hasXl) Then
				doc.FileDisplay = "1. DOC & XLS Attached"
			Elseif (hasDoc) Then
				doc.FileDisplay = "2. DOC Attached"
			Elseif (hasXl) Then
				doc.FileDisplay = "3. XLS Attached"
			Else
				doc.FileDisplay = "4. No Attachments"
			End If
		End If
		Call doc.Save(True, False)
		Set doc = view.GetNextDocument(doc)
	Loop
	
End Sub

Open in new window

scribla

ASKER
Hi Bill,

A couple of questions:

1. Rather than use a "DocumentsToUpdate" view could I not just run the agent against selected documents? as I'd prefer this method if possible.

2. I did indeed add the DocGetFileLocations to the script library. However I have changed your original example slightly as follows below. Just to prevent complete disaster when I try and run the agent, could you apply what I have done to your example above? I guess it should just be a copy and paste job on the IF/Else/Elseif sections, but I'd like you to confirm that what I have done to your example wont misbehave inside the agent.
Sub Postsave(Source As Notesuidocument)
	
      ' Save file metadata.
	Dim doc As NotesDocument
	Dim fileMap List As Variant
	Dim hasQuote As Boolean
	Dim hasCSS As Boolean
	Dim hasOA As Boolean
	Set doc = Source.Document
	Call DocGetFileLocations(doc, fileMap)
	If (Isempty(fileMap)) Then
		doc.FileDisplay = "No Attachments"
	Else
		Forall fileNames In fileMap
			Select Case Listtag(fileNames)
			Case "QuotationDocument"
				Forall fileName In fileNames
					If (Right(Lcase(fileName), 4) = ".doc") Then
						hasQuote = True
						Exit Forall
					End If
				End Forall
			Case "CostingSheet"
				Forall fileName In fileNames
					If (Right(Lcase(fileName), 4) = ".xls") Then
						hasCSS = True
						Exit Forall
					End If
				End Forall
			Case "OrderAcknowledgement"
				Forall fileName In fileNames
					If (Right(Lcase(fileName), 4) = ".doc") Then
						hasOA = True
						Exit Forall
					End If
				End Forall
			End Select
		End Forall
		If (hasQuote) Then
			doc.QuoteAttached = "Yes"
		Else 
			doc.QuoteAttached = "No"
		End If			
		If (hasCSS) Then
			doc.CSSAttached = "Yes"
		Else 
			doc.CSSAttached = "No"
		End If			
		If (hasOA) Then
			doc.OrderAckAttached = "Yes"
		Else 
			doc.OrderAckAttached = "No"
			
		End If
	End If			
	
	Call doc.Save(True, False)
	
End Sub

Open in new window

ASKER CERTIFIED SOLUTION
Bill-Hanson

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
scribla

ASKER
Very sorry for leaving this question, it has not been abandoned, I've just been busy with another project.
I'm having a play with your code examples now.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
scribla

ASKER
I didn't get very far I'm afraid. I created a new lotus script library and pasted your 'UpdateFileData' code in, when I save it says "Untitled: UpdateFileData: 7: Not a sub or function name: GETDOCFILELOCATIONS"

Line 7 = Call DocGetFileLocations(doc, fileMap)

I do have DocGetFileLocations saved in my script library already, so I don't understand what this problem is.
Bill-Hanson

It's hard to say what the problem is without seeing your code.  Please post the entire library.
scribla

ASKER
My bad, I was trying to create a new library.. Now pasted into the original library along side GetDocFileLocations and no error.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
scribla

ASKER
I have got as far as step 3. Creating the agent. When I try and save the agent I get the error "Not a sub or function name: UPDATEFILEDATA"

Not sure I've gone about this the right way. At the moment I have a single doc/object in my script library called 'DocGetFileLocations'

This contains:

GetDocFileLocations
ArrayAdd
ArrayAppendEx
ArrayElements
ArrayTrimArray
ArrayIsMember
ArrayCreate
UpdateFileData

The code for GetDocFileLocations is as follows in code snippet below. UpdateFileData is as you code snippet posted above.
Sub DocGetFileLocations(doc As NotesDocument, fileMap List As Variant)
	
	'/**
	' * Locates all file attachments in a document and returns the result in a hash table (list).
	' * @param doc The document that contains the attachments.
	' * @param fileList (Return) A hash table (list) used to store and return the results of this function.
	' */
	
	Dim allFiles As Variant ' all files embedded within the specified document regardless of which (if any) richtext field contains them.
	Dim rtFiles As Variant ' files found embedded within any rich text field.
	Erase fileMap ' clear the return param.
	
	' Get all attachment names.
	allFiles = ArrayTrimArray(Evaluate("@AttachmentNames", doc))
	If (Isempty(allFiles)) Then Exit Sub
	
	' Check all richtext items for embedded files.
	Forall item In doc.Items
		If (item.Type = RICHTEXT) Then
			If (Not Isempty(item.EmbeddedObjects)) Then
				Forall obj In item.EmbeddedObjects
					fileMap(item.Name) = ArrayAdd(fileMap(item.Name), obj.Name)
					rtFiles = ArrayAdd(rtFiles, obj.Name)
				End Forall
			End If
		End If
	End Forall
	
	' Get the files that are not embedded within an item.
	Forall file In allFiles
		If (Not ArrayIsMember(rtFiles, file, False)) Then
			fileMap("$DOCUMENT") = ArrayAdd(fileMap("$DOCUMENT"), file)
		End If
	End Forall
	
End Sub

Open in new window

Bill-Hanson

Did you remember to include the library by adding a "Use" statement in the agent's "Options" module?

    Use "DocGetFileLocations"

If you already included the library, please post the agent code for me to evaluate.
scribla

ASKER

Thats works great, thanks for bearing with me on this one.
I have some other functions I'd live to implement based on this code, I'll put questions up in due course.

Dan.
Your help has saved me hundreds of hours of internet surfing.
fblack61
scribla

ASKER
Many thanks once again Bill.
Bill-Hanson

No problem.  Glad to help.