Getting values from profile document - lotus-notes

I have some problem getting the value from the profile document. For creation, I followed these instructions:
Creating a profile form
1.Create a form with fields to hold the values you want to store in profile documents.
2.Choose Design - Form Properties and deselect "Include in Menu. and "Include in Search Builder"
3.Save the form.
4.Do not include the form in any view.
In the form I have only one field that is computed when composed (a number), with a computed value "0"
But with this code I can't retreive the field value:
Dim session as New NotesSession
Dim db as NotesDatabase
Dim doc as NotesDocument
Set db=session.CurrentDatabase
Set doc=db.GetProfileDocument("nameofprofiledoc")
dim number as integer
number=doc.fieldname(0)
Isprofile return true, but number is always "". For some reason it never gets the value

Perhaps it is because you haven't saved the document into the database yet. You can create an action button that let's you edit the document and then save it:
#Command( [EditProfile] ; formname );

Computed field formulas are not executed when you call GetProfileDocument. That's because GetProfileDocument is a "back-end" method. The form, with its various field definitions and formulas is used by the "front-end". (There's one exception: there's a ComputeWithForm method available in the back-end classes.) Anyhow. GetProfileDocument either loads a previously saved profile doc, or creates a new one that is essentially empty. #Ken's answer tells you how to manually create the profile document and save it so your code will find it. As an alternative, you can do the initialization in your code like this:
if ! doc.hasItem("fieldname") then
doc.replaceItemValue("fieldname",0)
end if
number=doc.fieldname(0)
That way you won't be dependent on someone manually creating the profile document. But if you are accessing the profile document from multiple places in code, and you can't predict which code might execute first, then you're probably going to want to create a script library with functions (or a class) and wrap GetProfileDocument in your own function (or method) to insure that all code paths will do the initialization properly.

As Richard mentions, when you call the method GetProfileDocument, the profile is created as a blank document, if not found in the database, (it will only have some initial fields that hold the profile name, conflict action, last editor)..
To initialize the profile, you might try to either:
1) Program the Form's QuerySave event to copy all items to the profile (then cancel the Save, to avoid storing the data in a regular document).
Sub Querysave(Source As Notesuidocument, Continue As Variant)
Dim db As NotesDatabase
Dim curdoc As NotesDocument
Dim profile As NotesDocument
Set curdoc = Source.Document
Set db = curodc.ParentDatabase
Set profile = db.GetProfileDocument(curdoc.Form(0))
Call curdoc.CopyAllItems(profile, True)
Call profile.Save(True, False)
Continue = False 'Don't allow the form to be saved to a regular document.
End Sub
Or:
2) Call GetProfileDocument to create a new profile or get an old one (you can tell the difference by checking the IsNewNote property. Then assign it a Form name, and compute it with this form.
In an Agent or an Action:
Sub InitializeProfile
Dim s As New NotesSession
Dim db As NotesDatabase
Dim profile As NotesDocument
Set db = s.CurrentDatabase
Set profile = db.GetProfileDocument("MyForm")
If profile.IsNewNote Then
Call profile.ReplaceItemValue("Form", "MyForm")
Call profile.ComputeWithForm(False, False) 'This will create the computed fields with their default values in the profile.
Call profile.Save(True, False)
End If
End Sub

Related

Change built-in Document properties without opening

I am attempting to run the below line of code in a sub. The purpose of the sub overall is to automatically create agendas for recurring meetings, and notify the relevant people.
'Values for example;
MtgDate = CDate("11/06/2020")
Agenda ="Z:\Business Manual\10000 Management\11000 Management\11000 Communications\Operations Meetings\11335 - OPS CCAR Performance Review Agenda 11.06.20.docx" 'NB it's a string
'and the problematic line:
Word.Application.Documents(Agenda).BuiltinDocumentProperties("Publish Date") = MtgDate
Two questions:
1) Can I assign a document property just like that without opening the document? (bear in mind this vba is running from an excel sheet where the data is stored)
2) Will word.application.documents accept the document name as a string, or does it have to be some other sort of object or something? I don't really understand Word VBA.
Attempts so far have only resulted in
runtime error 427 "remote server machine does not exist or is
unavailable"
or something about a bad file name.
Although Publish Date can be found under Insert > Quick Parts > Document Property it isn't actually a document property. It is a "built-in" CustomXML part, a node of CoverPageProperties, and can be addressed in VBA using the CustomXMLParts collection.
The CustomXML part is only added to the document once the mapped content control is inserted.
Below is the code I use.
As already pointed out for document properties the document must be open.
Public Sub WriteCoverPageProp(ByVal strNodeName As String, ByVal strValue As String, _
Optional ByRef docTarget As Document = Nothing)
'* Nodes: Abstract, CompanyAddress, CompanyEmail, CompanyFax, CompanyPhone, PublishDate
'* NOTE: If writing PublishDate set the content control to store just the date (default is date and time).
'* The date is stored in the xml as YYYY-MM-DD so must be written in this format.
'* The content control setting will determine how the date is displayed.
Dim cxpTarget As CustomXMLPart
Dim cxnTarget As CustomXMLNode
Dim strNamespace As String
If docTarget Is Nothing Then Set docTarget = ActiveDocument
strNodeName = "/ns0:CoverPageProperties[1]/ns0:" & strNodeName
strNamespace = "http://schemas.microsoft.com/office/2006/coverPageProps"
Set cxpTarget = docTarget.CustomXMLParts.SelectByNamespace(strNamespace).item(1)
Set cxnTarget = cxpTarget.SelectSingleNode(strNodeName)
cxnTarget.Text = strValue
Set cxnTarget = Nothing
Set cxpTarget = Nothing
End Sub
You cannot modify a document without opening it. In any event, "Publish Date" is not a Built-in Document Property; if it exists, it's a custom one.
Contrary to what you've been told, not all BuiltinDocumentProperties are read-only; some, like wdPropertyAuthor ("Author"), are read-write.
There are three main ways you could modify a Word document or "traditional" property (which are the ones you can access via .BuiltInDocumentProperties and .CustomProperties):
a. via the Object Model (as you are currently trying to do)
b. for a .docx, either unzipping the .docx, modifying the relevant XML part, and re-zipping the .docx.
c. For "traditional" properties, i.e. the things that you can access via .BuiltInDocumentProperties and .CustomDocumentProperties, in theory you can use a Microsoft .dll called dsofile.dll. But it hasn't been supported for a long time, won't work on Mac Word and the Microsoft download won't work on 64-bit Word. You'd also have to distribute and support it.
But in any case, "Publish Date" is not a traditional built-in property. It's probably, but not necessarily, a newer type of property called a "Cover Page Property". Those properties are in fact pretty much as "built-in" as the traditional properties but cannot be accessed via .BuiltInDocumentProperties.
To modify Cover Page properties, you can either use the object model or method (b) to access the Custom XML Part in which their data is stored. Method (c) is no help there.
Not sure where your error 427 is coming from, but I would guess from what you say that you are trying to see if you can modify the property in a single line, using the fullname of the document in an attempt to get Word to open it. No, you can't do that - you have to use GetObject/CreateObject/New to make a reference to an instance of Word (let's call it "wapp"), then (say)
Dim wdoc As Word.Document ' or As Object
Set wdoc = wapp.Documents.Open("the fullname of the document")
Then you can access its properties, e.g. for the read/write Title property you can do
wdoc.BuiltInDocumentProperties("Title") = "your new title"
wdoc.Save
If Publish Date is the Cover Page Property, once you have a reference to the Word Application and have ensured the document is open you can use code along the following lines:
Sub modPublishDate(theDoc As Word.Document, theDate As String)
' You need to format theDate - by default, Word expects an xsd:dateTime,
' e.g. 2020-06-11T00:00:00 if you only care about the date.
Const CPPUri As String = "http://schemas.microsoft.com/office/2006/coverPageProps"
Dim cxn As Office.CustomXMLNode
Dim cxps As Office.CustomXMLParts
Dim nsprefix As String
Set cxps = theDoc.CustomXMLParts.SelectByNamespace(CPPUri)
If cxps.Count > 0 Then
With cxps(1)
nsprefix = .NamespaceManager.LookupPrefix(CPPUri)
Set cxn = .SelectSingleNode(nsprefix & ":CoverPageProperties[1]/" & nsprefix & ":PublishDate[1]") '/PublishDate[1]")
If Not (cxn Is Nothing) Then
cxn.Text = theDate
Set cxn = Nothing
End If
End With
End If
Set cxps = Nothing
As for this, "Will word.application.documents accept the document name as a string", the answer is "yes", but Word has to have opened the document already. as mentioned above. Word can also accept an integer index into the .Documents collection and may accept just the name part of the FullName string.
Finally, if you do end up using a "traditional Custom Document Property", even after you have set the property and saved the document (approximately as above) you may find that the new property value has not actually saved! If so, that's down to an old error in Word where it won't save unless you have actually visited the Custom Document Property Dialog or have modified the document content in some way, e.g. adding a space at the end.

Lock current document using lotusscript

I have a document and a copy of the document. I want to create a document lock for the document using LotusScript.
I have separately put the current document inside Computer view and copy document inside Draft view. Below here the action to create a copy.
Create copy
Sub Click(Source As Button)
Dim ns As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim newdoc As NotesDocument
Dim dc As NotesDocumentCollection
Set db= ns.CurrentDatabase
Set dc= db.UnprocessedDocuments
If dc.Count<>1 Then
Messagebox "No or too many documents selected"
Exit Sub
End If
Set doc= dc.GetFirstDocument
Set newdoc= doc.CopyToDatabase(db)
Call newdoc.ReplaceItemValue("PStatus", "Draft")
Call newdoc.Save(True, False)
End Sub
Save Button
Sub Click(Source As Button)
Dim session As New NotesSession
Dim workspace As New NotesUIWorkspace
Dim db As NotesDatabase
Dim uidoc As NotesUIDocument
Dim doc As NotesDocument
Dim view As NotesView
Set uidoc = workspace.CurrentDocument
Set db = session.CurrentDatabase
Set view = db.GetView("Draft")
Set doc = view.GetDocumentByKey("Draft", True)
vpswd = Inputbox$("Pls input code to save :")
If vpswd = "o" Then
uidoc.EditMode = True
Set doc = uidoc.Document
Set doc = view.GetFirstDocument
If doc.PStatus(0) = "Draft" Then
Set newdoc= doc.CopyToDatabase(db)
Call newdoc.ReplaceItemValue("PStatus", "Active")
Call newdoc.Save(True, False)
End If
Call uidoc.FieldSetText("SaveOptions" , "1")
Call uidoc.Save
Call uidoc.Close
End If
End Sub
How can I lock a current document every time I create a copy of the document? E.g current document will lock when the copy document created.
Another question is, for copy document, after I saved, I want to replace the current document as a copy document and a copy document will be a live document. While the current document will not be deleted from the database but deleted from Computer view and displayed in the "Archived" view.
And inside Draft view, copy document will be deleted from view. Any help will be appreciated. Thanks!
Locking a document should be implicit. Make sure that you use the Status field in all documents. E.g. when you create the copy, set the status of the copied document to "Copied" and the nw documof nt to "Draft". You have to cover all different status changes. Best is also to add one field that contains a unique document Id that can never be changed. Maybe also add a version number.
Examples of statuses:
Draft: document under construction (only one, cannot be copied)
Current: valid document (only one, can be copied)
Copied: Current document that has been copied (only one, cannot be copied)
Archived: document that has been replaced (more than one, cannot be copied)
It might help to create a STD, a State Transition Diagram.
I have done something similar. When a new version, as I call it, is created, it is the "draft" document. The previous document is an "approved" document. User get to see only the approved until the new version is approved, then the older approved document is archived out of the db. If you want all versions to stay in the db, but only the newer document brought up, you could use what I call a HistoryID field. Basically I have a field on every document that has up to three values in it:
TheUNID
ParentUNID:TheUNID:Parent
TheUNID:ChildUNID:Child
The "theUNID" field is computed when composed so it never changes. If a new version or draft is created, the HistoryID would now have two values:
TheUNID
TheUNID:ChildUNID:Parent
This let's you know you now have a new draft and the document you are on is actually a parent. The "ChildUNID" is actually "theUNID" of the draft document you just created.
On the child document or the new draft document you put in the HistoryID:
TheUNID
ParentUNID:TheUNID:Parent
This way your draft knows who it's parent is.
In your code in your db, you just have any document that gets opened check the HistoryID field first. If there is a child, you take the user to the child. It doesn't matter what parent gets opened or how far back the generations go, your code continues to iterate through the HistoryID until the current child document is found that doesn't have a parent. Sound good?
Let me know if you need clarification.

How can Lotus Notes detect whether a document is currently being opened?

As title.
How can Lotus Notes detect whether a document is currently being opened?
The solution should without "Document locking" because of User's User needs.
I have 1 maindoc and 1 subdoc, but subdoc and maindoc are not parents.
I use the "IsUIDocOpen" but it just worked at currentdocument.
Is there any other way to do this?
If you ask just for one client, then this is doable without document locking, but it needs some advanced techniques:
You can use NotesUIWorkspace to get a currently open document for any given backend document if you set parameter "newInstance" to false.
To get the currently open document (as uidocument, but of course you can use .Document property to get NotesDocument from it) you use the following code. If it returns nothing then the document is not open:
Dim ses as New NotesSession
Dim ws as New NotesUIWorkspace
Dim docToGetFrontendFor as NotesDocument
Dim uidoc as NotesDocument
Set docToGetFrontendFor = .... 'somehow get the document you wanna have the frontend for
Call ses.SetEnvironmentvar( "PreventOpen" , "TRUE" )
Set uidoc = ws.EditDocument( False, docToGetFrontendFor, False, "", True, False )
If not uidoc is Nothing then '-document was open already
'- do whatever with the frontend- document
Why the ses.SetEnvironmentvar( "PreventOpen" , "TRUE" )?
The EditDocument opens the document regardless of it being open already or not.
You need to prevent the document from opening, if it is not already open. Therefor you manipulate the "QueryOpen"- Event of the Form of the document:
Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
Dim ses as New NotesSession
Dim strPrevent as String
strPrevent = ses.GetEnvironmentstring( "PreventOpen" )
Call ses.SetEnvironmentVar( "PreventOpen" , "" )
If strPrevent = "TRUE" Then Continue = False
End Sub
So: The document does NOT open, if PreventOpen is set, so if it is not already open it will stay closed.
This approach has one big downside: The Notes Client has a "BUG": If you open a document and save it and then open it again with my code, then it will Open in a second window DESPITE the parameter "newInstance" set to false unless you closed and reopened that document.
Explained:
Create Document
Save document
Close document
Reopen document
Use my code
==> Works as the code just "reuses" the window
Create Document
Save document
Use my code
==> Will try to open a second instance for the document and then return NOTHING as this new instance does not open because of the code...

Generating a document link coming from another form (Web)

I'm trying to generate document links from another form using a button I created (in pass through below). Upon clicking the button, an agent must run and document link/s should be generated, and the current form should still be in edit mode (web).
Here are the issues:
1. I am unable to generate document link/s coming from another form through the view. The key is PeopleID, the current document has the computed field which should match with another form.
2. When I click on the button, it redirects me to the agent page and says that the agent is done running (non-verbatim). It should still be on the current document (current page, only that the document link/s should be generated).
Below is the code I use on the form (in pass-through) for the button and JS function to run agent.
<input type="button" value="Generate Link" onclick="javascript:runAgent();">
<script language="JavaScript">
function runAgent() {
var path = document.forms[0].BaseLink.value; // BaseLink is the prefix url.
var completeUrl = path + '(GenerateDoc)?OpenAgent&UNID=' + document.forms[0].UniqueID.value;
self.location.href = completeUrl;
}
</script>
After this, I have a rich text field named "DocumentLink", computed.
For the agent code, here it is:
Dim session As New NotesSession
Dim db as NotesDatabase
Dim curDoc as NotesDocument
Dim difDoc as NotesDocument
Dim view as NotesView
Dim rtitem as NotesRichTextItem
Dim peopleID as String
Set db = session.currentDatabase
thisDocumentID = Right$(session.DocumentContext.query_string(0),32)
Set curDoc = db.GetDocumentByUNID(thisDocumentID) //For some reason I am not getting anything here.
Set view = db.GetView("MyView")
peopleID = curDoc.PeopleID(0)
Set difDoc = view.GetDOcumentByKey(peopleID,true)
If Not difDoc Is Nothing Then
Set rtitem = curDOc.GetFirstItem("DocumentLink")
rtitem.values = ""
Call rtitem.AppendDocLink(difDoc,"Link to other form")
Call curDoc.Save(True,False)
End If
Appreciate your help.
There are several issues with what you are doing.
First: The self.location.href = completeUrl; line in Javascript will redirect the browser to the agent which has no relationship to the currently selected or open document. Alternatives to this approach would be using AJAX techniques from jQuery or other framework to run your agent asynchronously. If you have not saved the current document then there might not be a UNID on the Query String using your current approach.
Second: You should put the PeopleId on the query string also so that the agent can read it. The agent should then parse the Query_String_Decoded to get the two elements UNID and PeopleId.
Third: your agent is not generating any output. You should use PRINT statements in the LotusSctipt to create some feedback. You can also create JavaScript Tags and calls to calls to redirect back to the original page/document.

$Ref flag reappears even after deletion

We have an Xpage based Web mail-in application. Some emails are coming with $Ref field (response document). We wanted to convert them into normal document by removing $Ref field so that it will no longer a response one. We are able to delete the $ref field but it reappears again after saving the documents from web interface(xpage) and it makes all such documents again response document. This started happening recently and working well earlier. Can you please suggest what is the root cause? How to stop it?
Sub Initialize
On Error GoTo ErrorHandler
Dim s As New NotesSession
Dim db As NotesDatabase
Dim coll As NotesDocumentCollection
Dim doc As NotesDocument
Dim count As Long
Set db = s.Currentdatabase
Set coll = db.Unprocesseddocuments
MessageBox "Count : " & coll.Count
'Exit Sub
count = 1
Set doc = coll.Getfirstdocument()
While Not doc Is Nothing
If doc.Hasitem("$Ref") Then
Call doc.Removeitem("$Ref")
Call doc.Save(false, false)
End If
Print count
count = count + 1
Set doc = coll.Getnextdocument(doc)
Wend
Exit Sub
ErrorHandler:
MessageBox "Error " & Error & " at line " & Erl
Exit Sub
End Sub
Try changing your save method to Call doc.Save(true, false).
This will force the document save, and also prevent creating a response.
Also verify that you are running the agent on a server not accessable to active users. Also verify that you are only running your agent once, and that it isn't enabled on multible replicas.
Have you tried using If(doc.isResponse) Then instead of If doc.Hasitem("$Ref") Then
Note: I am looking in the java editor, but assume that the isResponse method is also in LS.
Wheather a document is a response is controlled by a property of the used form. As long as you do not assign another form that is a "Document" and not a "Response", you will most probably not be able to remove the "isresponse"- flag. As already told: most probably your xpage saves the "frontend" document after your backend manipulation and resets the state (form validation enabled in xpage properties). But without source code of the xpage one cannot tell.
Check the form name. Emails can use either the "Memo" form or the "Reply" form. Emails using the Reply form are response documents. You may also need to change the form to "Memo".

Resources