Use ContentControls to insert insert LastSavedBy Name, Date and Time information into Word form

106 Views Asked by At

I've set up a word form with different sections, each section to be completed by a separate person. Each section of the form includes a combination of dropdown lists or free text fields set up using named Content controls. At the end of each section there is field for the staff member to record their name, the date (calendar icon), and a command button with an associated macro to save the form and protect the data once that section has been completed. While this enables the data to be protected it does not prevent person A from completing the form and entering person B's name. Note, this would not be expected, but traceability is required for regulatory purposes.

I would like to update the macro to protect the sections, save the file (currently working), and then immediately after saving, have the macro populate another field directly under the manually entered name and date with the Microsoft advanced properties of Last Saved By and the date and time. This would confirm the user.

My macro below (InsertMSSavedDetails()) will extract the Microsoft required data, but only if I manually click on the form and run the macro, and then it saves wherever I click on the form and won't save to the named ContentControl box. I'd like to automate this last step so that it is not reliant upon the user and the data is associated with particular section.

My form includes the following code:

Module
Sub ProtectFieldsSections2()
' protects Sections 1 and 2
If MsgBox("Do you want to Lock and Protect this section from further editing?", vbYesNo) = vbNo     
Then Exit Sub
Dim sec As Section
Dim cc As ContentControl

Set sec = ActiveDocument.Sections(2)
For Each cc In sec.Range.ContentControls
cc.LockContents = True
Next cc
End Sub

This document:
Private Sub CommandButton2_Click()
ProtectFieldsSection1
ProtectFieldsSection2
ActiveDocument.Save
End Sub

Current code for Adding Microsoft data - which technically works, but not in the manner I need:

Sub InsertMSSavedDetails()
'
ActiveDocument.SelectContentControlsByTitle ("MSSavedDetails")
    Selection.TypeText Text:="Check data: "
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
        "LASTSAVEDBY  ", PreserveFormatting:=True
    Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
        "SAVEDATE  \@ ""d/MM/yyyy h:mm:ss am/pm"" ", PreserveFormatting:=True
End Sub

Second issue with the above, is that it would only need to be added the once, when Sub CommandButton2_Click is first selected. If I were to update the Sub CommandButton2_Click, how would I stop if from repeating the cycle of save, insert Microsoft data, save, insert Microsoft data?

NOTE: Use of word vs PDF form. Presently, the form is used in word format, converted to PDF, and electronically signed, however this does not allow others to add their information to the remaining sections. Adobe LiveCycler has been used to design PDF forms but there were issues with maintaining images and graphs, and there were other issues experienced with the Adobe reader, so the option is to remain with word.

Thank you.

1

There are 1 best solutions below

1
On BEST ANSWER

Not sure I have completely understood the problems, but

The problem with inserting the field codes LASTSAVEDBY and SAVEDATE is that unless you "lock" them, their values will always reflect the most recent save. Also, if you want the fields to go in a content control, you have to use a rich text content control.

Perhaps better to

  1. save the document

  2. get the underlying property values (the ones that LASTSAVEDBY and SAVEDATE display) and insert them

  3. save the document

If you have content controls named (say)

Section1LastSavedBy

Section1SaveDate

Section2LastSavedBy

etc.

then

  • you know which commandbutton the user clicked so you know which section you are dealing with

  • your code can then look something like

     Private Sub CommandButton2_Click()
     ProtectFieldsSection1
     ProtectFieldsSection2
     With ActiveDocument
       .Save
       .SelectContentControlsByTitle("Section1LastSavedBy")(1).Range.Text = _
         .BuiltinDocumentProperties("Last Author").Value
       .SelectContentControlsByTitle("Section1SaveDate")(1).Range.Text = _
         format(.BuiltinDocumentProperties("Last Save Time").Value,"D/MM/YYYY h:mm:ss am/pm")
       .Save
     End With
    
     End Sub
    

If you want to construct the content control names programmatically based on Section number, you can.

If you want to lock the content controls against further editing, you can.

I am not sure what problem you are encountering here:

"Second issue with the above, is that it would only need to be added the once, when Sub CommandButton2_Click is first selected. If I were to update the Sub CommandButton2_Click, how would I stop if from repeating the cycle of save, insert Microsoft data, save, insert Microsoft data?"

unless you are using a Save event. If that's the problem we could revisit that part.

It's pretty difficult to stop people tampering with data in Word, but personally I would consider saving copies of these values in, e.g., a Custom XML Part (not mapped to the controls) or Document Variables - possibly also encrypt them - you can use Windows crypto APIs for that.

Incidentally, I suspect the problem you have with your existing code is that .SelectContentControlsBYTitle doesn't Select the controls in the normal Word sense. It just returns a collection of controls with that name.