Solved

SaveOptions Problem

Posted on 2013-01-11
18
1,276 Views
Last Modified: 2013-12-18
I just inherited a database from someone who quit.  it's a workflow database built off of a document library template from version 5 or 6.

I'm trying to prevent saving if the document is in an approved state (status = 3), and i've been running around in circles.

i updated the QuerySave event to include :

If note.Status(0) = "3" Then note.SaveOptions(0) = "1" Else note.SaveOptions(0) = "0"

There are a series of : note.RemoveItem("SaveOptions") statements in the QueryOpen and QuerySave events that I think is preventing my logic from working, but when I comment it out, users receive a "linked document cannot be found in the view" error.

the basic program flow is this :   originator creates a document, sends for review.  reviewer approves the document ( button has formula language to set status to 3, send doclink to originator)

once the approver approves the document...( sets status to 3) , i want to prevent editing to the document.

I attached a file with code from the queryopen, querysave and the approval button logic.

any help is appreciated.  thanks!
1.png
2.png
3.png
0
Comment
Question by:everetjo
  • 9
  • 9
18 Comments
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
The code isn't exactly right, I think. Could you try with

     If note.Status(0) = "3" Then note.SaveOptions = "1" Else note.SaveOptions = "0"

SaveOptions=0 means: don't save, don't ask!
SaveOptions=1 : always save, don't ask!
no SaveOptions field: always ask on close when modified.

There are some minor code mishaps but they don't change the execution.
0
 

Author Comment

by:everetjo
Comment Utility
Hi sjef,

i tried this code in querysave and i get that " the doucment cannot be found in the
error.png
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
I suppose the code should have been

     If note.Status(0) = "3" Then note.SaveOptions = "0" Else note.SaveOptions(0) = "1"

Do you want Notes to ask if the document is to be saved? If so, you only need

     If note.Status(0) = "3" Then note.SaveOptions = "0"

How come the document can be put in edit-mode when status=3 ??
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
The "doc cannot be found" error could be related, but I think it's a separate issue. Do all users get that error when closing a document?

Here some suggestions: http://www-01.ibm.com/support/docview.wss?uid=swg21115363
0
 

Author Comment

by:everetjo
Comment Utility
I'll try this one and post back.  i would prefer that you are not prompted to save when status is 3...ideally the user should be prompted with "cannot edit approved documents" or something...but that can wait

i can't really test whether or not the doc can be edited because i can't find it.

through the several SaveOptions iterations i've tried, the user is prevented from editing and saving existing docs..so that works.

the problem is that when the dB sends the doc link, the user gets the "cannot be found in the view message" and i can't find the document when browsing through the dbs...depsite rebuilding/refreshing views.
0
 

Author Comment

by:everetjo
Comment Utility
the "doc cannot be found" error is repeatable on mulitple workstations and remains despite clearing cache/rebuilding views etc.  what a runaround ;)
0
 

Author Comment

by:everetjo
Comment Utility
ok.  this appears to be working but some functionality is broken.

my "submit approval" button uses formula language to say status = 3 ( approved) this sets off other events that aren't working ( calcuate approval date, etc)  because the doc is not editable.

do i need to change my button code to lotus script?
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
Ok. To prevent editing the document, you can more easily use the QueryOpen and QueryModeChange events. In principle, all you need is code that sets Coninue to False if status=3. Much easier to prevent editing a "closed" document.

Can you post the code that generates the mail, with the doclink?
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
Maybe you don't need LotusScript, Formula is powerful enough. If you post the code in a code-block, you make it possible for me to copy/modify/paste your code.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:everetjo
Comment Utility
the current state is all functionality is there, except approved docs can be edited.  doclinks, et all are working.

status is a number field that is "computed when composed"
there is no SaveOptions field on the actual notes document...only referenced in the QuerySave, QueryOpen events

The first code block is from the "submit approval" button :  sets status to 3, makes approval date and send link to orginator...working correctly now

  @PostedCommand ([EditDocument]; "1");
FIELD status := 3;
FIELD Roptions := "A";


@Prompt([YesNo]; "REMINDER";"Send notification to " + @Name([CN]; From) + " that your approval is complete?");

@MailSend(From;admin@comp.com;null;"Your change document was approved";"Change number:";"Number";  [IncludeDoclink]);

@PostedCommand([FileSave]);
@PostedCommand([FileCloseWindow])

Open in new window


QueryOpen event :

 Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
	If Isnewdoc Then Exit Sub
	Set note = source.document
	
'remove all of these so they can ger resest with default values each time the doc is opened     
	note.RemoveItem("SaveOptions")
	note.RemoveItem("CurrentUser")
	note.RemoveItem("SubmitNow")
	note.RemoveItem("NSubmitNow")
	note.RemoveItem("Resubmit")
	note.RemoveItem("SendError")
	note.RemoveItem("WebCategories")
	
End Sub 

Open in new window


Querysave event :

Sub Querysave(Source As Notesuidocument, Continue As Variant)
	Dim ws As New NotesUIWorkspace     
	
	Set session = New NotesSession
	Set db = session.CurrentDatabase
	If note Is Nothing Then Set note = source.Document
	
	note.RemoveItem("SaveOptions")
	
	If note.NSubmitNow(0) = "1" Then NSubmitNow = True
	
'ParallelReviewCheck
	If note.ReviewType(0) = "2" And note.complete(0) = "1" Then
		Goto PContinue
	End If
	
	
'Serial review check: If we are not submitting for review, we don't need to do the rest of this     
	If (Not(NSubmitNow)  Or note.Status(0) = 3) And note.Resubmit(0) = "0" Then Exit Sub
	
PContinue:     
'Validate that the ReviewerList does not include the originator     
	If ListIncludesOriginator Then
'		Call note.replaceitemvalue("$DocLib", "RevCycle")
		Messagebox GetString(17) & GetString(18), 0, GetString(41)
		continue = False
		If FieldName = "Reviewer List" Then
			source.GoToField("ReviewerList")
		Else
			source.GoToField("NewReviewer")
		End If
		Exit Sub
	End If
	
'Validate that ReviewTime is not blank.  if it is, set to "0" (no time limit)
	Set item = note.GetFirstItem("ReviewTime")
	If note.ReviewWindow(0) = "" Then
		note.ReviewWindow = "0"	
	End If
	
	
'Validate that ReviewTime has a valid entry if ReviewWindow is not 0
	Set item = note.GetFirstItem("ReviewTime")
	If note.ReviewWindow(0) <> "0" Then
'This verifies that it is not 0 or blank or a string
		If item.Text = "" Or item.Text = "0" Or item.Text Like "*ERROR*" Then
			InvalidReviewTime = True
'This verifies that it is a whole number > 0          
		Elseif note.ReviewTime(0) < 1 Or Int(note.ReviewTime(0)) <> note.ReviewTime(0) Then
			InvalidReviewTime = True
		End If
		If InvalidReviewTime Then
			FieldName = "Time Limit"
			Messagebox GetString(16) & GetString(18), 0, GetString(41)
			continue = False
			source.GoToField("ReviewTime")
			Exit Sub         
		End If
	End If
	
'Validate that the ReviewerList is not blank     
	If note.ReviewerList(0) = "" And note.NSubmitNow(0) = "1" Then
		FieldName = "Reviewer List"
		Messagebox GetString(19) & GetString(18), 0, GetString(41)
		continue = False
		source.GoToField("ReviewTime")
		Exit Sub
	End If
	
'Set this global variable so the scriptlib knows whether to put up messageboxes or pages          
	ClientType = "Notes"
'If the send (function in the SubmitForReview scriptlib) was successful, then save and close
'SaveOptions supresses the save prompt          
	
	If note.ReviewType(0)="1" Then
		If SendToNext Then
			note.SaveOptions = "1"
			source.Close
		Else
			Continue = False
			source.Refresh
		End If
	End If
	
	If note.ReviewType(0)="2" Then
		If SendToAll Then
			
			note.SaveOptions = "1"
			source.Close
		Else
			Continue = False
			source.Refresh
			
		End If
	End If
	
finish:
	ws.ViewRefresh
End Sub

Open in new window


queryclose :

 Sub Queryclose(Source As Notesuidocument, Continue As Variant)
	Dim rtitem As Variant
	
	If note Is Nothing Then Exit Sub
	If Not(note.HasItem("CopyBody")) Then Exit Sub
	
'we already copied the rest of the document, now we need to copy the body field
	Set savenote = db.GetDocumentByUNID(note.OriginalSaved(0))
	If note.HasItem("BodyText") Then
		Set rtitem = note.GetFirstItem("BodyText")
		savenote.RemoveItem("BodyText")
		Call rtitem.CopyItemToDocument(savenote, "BodyText")
	End If
	If note.HasItem("Specs") Then
		Set rtitem = note.GetFirstItem("Specs")
		savenote.RemoveItem("Specs")
		Call rtitem.CopyItemToDocument(savenote, "Specs")
	End If
	If note.HasItem("Specs1") Then
		Set rtitem = note.GetFirstItem("Specs1")
		savenote.RemoveItem("Specs1")
		Call rtitem.CopyItemToDocument(savenote, "Specs1")
	End If
	If note.HasItem("TestingStrategy") Then
		Set rtitem = note.GetFirstItem("TestingStrategy")
		savenote.RemoveItem("TestingStrategy")
		Call rtitem.CopyItemToDocument(savenote, "TestingStrategy")
	End If
	If note.HasItem("TestingStrategy_1") Then
		Set rtitem = note.GetFirstItem("TestingStrategy_1")
		savenote.RemoveItem("TestingStrategy_1")
		Call rtitem.CopyItemToDocument(savenote, "TestingStrategy_1")
	End If
	savenote.save True, True, True
	note.RemoveItem("CopyBody")
	note.save True, True, True
	
End Sub  

Open in new window

0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
Some remarks (I don't know how much originates from the Doc Library template):
- I think you don't need the SaveOptions field, you can do without it.
- I hope there is an Option Declare or Option Explicit in your code (it's a good habit to always declare variables)
- on the other hand, if there is such a line, it might explain some coding mistakes
- QuerySave: a GoTo statement and a label ?? Now really...
- QuerySave, line 27: the sudden appearance of FieldName...
- QuerySave, lines 36 and 43 are duplicates, one is superfluous
- QuerySave, line 47: is InvalidReviewTime ever set to False ?
- QuerySave: why are all field evaluations in the QuerySave, and not in the fields themselves?

The code for the submit approval button can't be correct. Whether the user answers Yes or No on the @Prompt, a mail is always created and sent.
Plus, I don't understand the FIELD status:=3 code, for two reasons:
- the field is, as you said, a computed when composed field, which means that its value can't be changed using formula
- your tests in LotusScript for the value of that field are always using a string value "3"

Some more code mishaps here, I think I'd better warn you about them: this line
     savenote.RemoveItem("TestingStrategy_1")
is probably a mix of two types of statements. It works, so you don't really need to change it, but I think you have to be aware of the potential issue. What was probably meant with the code is either one of the following 2 lines:
     savenote.RemoveItem "TestingStrategy_1"
     Call savenote.RemoveItem("TestingStrategy_1")

What's the difference with your statement? Well, what your statement actually represents is this statement:
     Call savenote.RemoveItem(("TestingStrategy_1"))
Big deal, you say. Yes, in this case, but I had this very type of problem once and spent half a day to find why my code didn't work.

An example, let's see if you understand the problem... ;-)

Sub func(v as Integer)
     v= v + 2
End Sub

Quiz: what is printed by this code:

Dim v As Integer
v= 1
func(1)
Print v
0
 

Author Comment

by:everetjo
Comment Utility
This is fun. I think it will print 1 because v= 1 and this function takes in the number 1 instead of v so v isn't changed by the function. It should be print func(v). In that case the function will return 3
0
 

Author Comment

by:everetjo
Comment Utility
I honestly haven't worked on this database before.  It was given to me because someone quit.
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
It will indeed print 1. Print func(1) will probably yield an error, or Null, for the function returns nothing.

Next question.
What will this code do:

Dim v As Integer
v= 1
func(v)
Print v

I understood that you inherited the application. IMHO someone should have reviewed the code...
0
 

Author Comment

by:everetjo
Comment Utility
This looks like it will print 1 also since the function doesn't return anything and your not printing the functions output, only v
0
 
LVL 46

Expert Comment

by:Sjef Bosman
Comment Utility
Before I tell you if you're right or wrong, here one last question: what do you think the following code will print?

Dim v As Integer
v= 1
Call  func(v)
Print  v

And no, itis not the same code as the previous question. Look carefully, and spot the difference.
0
 

Author Comment

by:everetjo
Comment Utility
This has a call statement so it will return an error
0
 
LVL 46

Accepted Solution

by:
Sjef Bosman earned 500 total points
Comment Utility
Nope, it works, no errors. Moreover, this one finally prints 3.

I'll explain. Parameter passing in LotusScript is by reference, unless you pass a simple value or an expression as a parameter or when you use the ByVal keyword. In the case of func(v), which is actually not a function but a subroutine, the parameter v is passed by reference.

The 1st example, the sub gets a parameter with a value that cannot be referenced. Inside the function, the local variable v is set to 3 but outside nothing happens.

The last question prints 3, because the variable v starts with a value 1, it is passed to the sub by reference, so the function adds 2 to the real v outside the sub. When func ends, v has indeed the value 3.

Now for the 2nd example, which I should have asked last, for the effect. There is no Call statement, but it is syntactically correct. The statement
     func v
is equivalent to
     Call func(v)
But what happens when you write
     func(v)
The compiler reads this as
     call subroutine "func" with one parameter, the expression (v). That expression is evaluated, it yields the value 1, so func is actually called with a value-parameter 1. Noing is changed outside func when it returns from the call.

So the difference between
     func(v)
On the one hand, and
     func v
or
     Call func(v)
is that in the last case the parameter v is passed by reference (its value can be changed by a sub), whereas in the first case (v) is an expression! The result is calculated first, then passed to the sub as a value parameter.

In my case, I had defined a subroutine
     Sub MySort(v As Variant)
     .... Lots of code
     End Sub
and I called it using
     MySort(somearray)
What happened? Nothing! The array wasn't sorted. I checked wi the debugger, followed the execution, and right until the last staement of Sort everything went perfectly. Upon return, the old value was magically there. The explanation is that the sub is called with a value, i.e. the result of the expression (somearray), because the line should be read like
    MySort      (Somearray)

Once i changed it into
     Call MySort(somearray)
it started to work.

Sorry for the lengthy explanation...
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Problem "Can you help me recover my changes?  I double-clicked the attachment, made changes, and then hit Save before closing it.  But when I try to re-open it, my changes are missing!"    Solution This solution opens the Outlook Secure Temp Fold…
This article covers general Notes 8.5 troubleshooting information including recreating the Notes\Data folder.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now