top of page

Item List

The macros below will automatically save a document after assembly. The macros will work "as-is" (as-are?). Simply save the appropriate macro to the macro directory (WordPerfect) or to a global add-in template (Word). The WordPerfect macro is also available for download.

Quick Overview: These macros are all based on the same concept. The user is prompted for the document's filename by HotDocs during assembly. This is just a HotDocs text variable, called TextVar in the explanations below. This text variable is placed somewhere in the template surrounded by a bookmark. When assembly is complete, the macro looks for the bookmark, extracts the value of TextVar from within it, and saves the document using this value as the filename.

Directory: You should be able to add directory-selecting functionality fairly easily. One option is to create a HotDocs multiple choice variable for the directory and include that variable within the bookmark with TextVar:

[Bookmark]«Directory»«TextVar»[Bookmark]

The second Word macro below demonstrates how to have your macro determine the directory, and additionally how to add an entry for the document in a Lawbase database.

Invoking the Macro: The macros are all invoked in the same manner, regardless of whether you use Word or WordPerfect. To invoke the macro you must use a PLAY instruction at the end of the document. In other words, make sure that the PLAY is the very last thing in the document. Otherwise, the saved document will be incomplete. To create a PLAY instruction, follow the directions found in Computation #0108: Running a Macro During Assembly.


Code
Sub SaveDoc()

   Dim DocNameStr As String
   Dim DocPathStr As String
   Dim DocNameChoppedStr As String
   Dim DocDriveLtr
   Dim nextSerial

   ' Find the bookmark called DocumentName to get the document's save name
   Selection.GoTo What:=wdGoToBookmark, Name:="DocumentName"

   ' Select all of the text in the DocumentName line
   Selection.EndKey Unit:=wdLine, Extend:=wdExtend

   ' Dump the searched text into a string for use in saving the file
   DocNameStr = Selection.Text
   DocNameChoppedStr = Selection.Text

   ' Use the last name of the person to whom the document is created to
   ' pick the directory where it will be stored
   DocDriveLtr = Left(DocNameChoppedStr, 1)

   ' Set the string of the drive and path to where the document will be saved
   ' !! MODIFY THIS TO MATCH YOUR DRIVE CONFIGURATION !!
   DocPathStr = "//SERVERNAME/SomePath/" & DocDriveLtr & "/"

   ' Delete the bookmark from the document
   Selection.Delete

   ' Save the file using the directory that was specified above and the name
   ' that is designated by DocNameStr
   With Dialogs(wdDialogFileSaveAs)
      .Name = DocPathStr & DocNameStr & "_"
      .Show
   End With

   ' Begin section to set office link and throw the link to the document
   ' in there as well
   Selection.GoTo What:=wdGoToBookmark, Name:="DocuSerial"

   ' Get the saved documents name and path
   DocNameStr = ""
   DocPathStr = ""
   DocNameStr = ActiveDocument.Name
   DocPathStr = ActiveDocument.Path

   Dim SerialNum
   Dim DBLawbase
   Dim dsSerialNum
   Dim dsAddOfficeLink

   SerialNum = Trim(Selection)

   ' Create connection object to connect to the database
   Set DBLawbase = CreateObject("ADODB.Connection")
   DBLawbase.connectionstring = "DSN=Lawbase;uid=sa;pwd=sa;"
   DBLawbase.Open

   ' Get last serial number so we can add one to it
   Set dsSerialNum = CreateObject("adodb.Recordset")
   nextSerial = "select max(serial) + 1 as newserial from office_link"
   dsSerialNum.Open nextSerial, DBLawbase, 3, 3

   ' Insert all values into the officelink table for the serial in question
   Set dsAddOfficeLink = CreateObject("ADODB.RecordSet")
   SQL = "insert into office_link values (" & dsSerialNum.Fields("newserial") & ", " & SerialNum & ", 0, 0, '" & DocPathStr & "/" & DocNameStr & "', '" & DocNameStr & "', getdate(), 'AUTO', 'Word')"
   dsAddOfficeLink.Open SQL, DBLawbase, 3, 3

   ' Kill serial number off of document
   Selection.Delete

   ' Resave after cleaning
   ActiveDocument.Save

   ' Cleanup
   dsSerialNum.Close
   Set dsSerialNum = Nothing
   'dsAddOfficeLink.Close
   Set dsAddOfficeLink = Nothing
   DBLawbase.Close
   Set DBLawbase = Nothing

   End

End Sub


Explanation
Our frim uses Lawbase as a frontend w/ a SQL Server backend. Since there is very little custom coding for Lawbase, I wrote this to simplify the ever-enthralling task of choosing the correct directory to save the document in and linking the document to the matter in our database. We use a directory with subdirectories of the alphabet. For example, documents involving John Doe would go in:

//SERVER/SomePath/D/...

I think it is eaisier to use DOS names instead of long file names.

First thing anyone wanting to use this code needs to do is insert two bookmarks into their document. The first is called DocumentName, and the second DocuSerial. Here is the format I use (you will want to use your own naming conventions):

DocumentName - [Bookmark]«lb_link_header_client_lname», «lb_link_header_client_fname», «lb_template», «TODAY:3 June 1990»[Bookmark]
DocuSerial - [Bookmark]  «lb_header_serial»  [Bookmark]

NOTE: «lb_header_serial» in DocuSerial must be padded with spaces on either side if it is not long enough to be a Bookmark.

I just make the text white so that it will not be visible in the document and will not confuse anyone.

110. Auto-Save Macros

Word and WordPerfect macros for automatically saving your document after assembly.

109. Count Weekdays or Weekends

Determine the number of weekdays or weekends that fall within a given range of dates.

You can play a word processor macro during document assembly by inserting a PLAY instruction into the template.

To insert a PLAY instruction:

Position the cursor at the point in the template where you want the macro to be run.
Insert a HotDocs variable or instruction (to insert the correct chevron characters).
Delete the text between the chevrons and replace it with PLAY "macroname" (where macroname is the name of the macro). Be sure to use straight quotes (" ") instead of curly or smart quotes.
In WordPerfect or Ami Pro, macroname can be a file name (if the macro is stored in the default macro directory) or a full path (if it is not). For example: MYMACRO.WCM or C:\TEMP\MYMACRO.WCM.

In Word, macroname is just a macro name. The macro may be stored in the template you are editing, or it may be stored in a global template (such as HDGLOBAL.DOT) or in NORMAL.DOT. In Word and Ami Pro, and in WordPerfect templates assembled in the word processor (slow-assembled), PLAY instructions are executed as they are encountered. For WordPerfect templates that are assembled from the HotDocs library (fast-assembled), PLAY instructions are stored until assembly is complete, then the assembled document is loaded into the word processor and the stored PLAY instructions are executed. This means that WordPerfect templates with PLAY instructions operate differently depending on how they are assembled, unless the PLAY instructions are placed at the end of the template.

You should be careful that the macro used with a PLAY instruction doesn't change the active cursor location, or HotDocs may skip over some text of the template that needs to be processed for assembly.

108. Running a Macro During Assembly

How to run a macro during assembly.

HotDocs does not provide a DAY OF YEAR() model. This computation provides that functionality. For a given DateVar, the computation determines the day of the year from 1-365 (366 for leap year). For example: New Year's Day is day 1, Valentine's Day is day 45, etc.

The day of year is found by determining the DAYS FROM January 1 of the year in question to the given DateVar (you could also use TODAY). We then add one day (otherwise Jan. 1 would be day zero). The resulting day of year is returned as a number value.

106. Day of the Year

Determine the day of the year (from 1 - 365/6).

HotDocs provides pick lists to allow users to select data from data records on dialogs. However, HotDocs permits only one pick list to be associated with a particular dialog and does not permit multiple records to be selected for one dialog. (Note: pick lists do permit you to select multiple records for spreadsheet-style repeating dialogs, but you cannot select multiple records on a particular repeat iteration. For example, you can select John as trustee at the first repetition, Helen at the second repetition, and so on, but you can't select John and Helen as co-trustees on one repetition.)

The following discussion presents a strategy for creating a system independent of pick lists that overcomes these limitations. The discussion assumes some familiarity with database terminology. HotDocs Pro 5.x is required.

To break the problem down into three parts:

1.	Aside from pick lists and external databases, how can we store data in a database table format in HotDocs?
2.	How can we allow users to select records from more than one list on a single dialog?
3.	How do we extract data fields from the table and insert them in the template based on the user's selections?

First, we figure out our table structure; in other words, what are the field names and variable types for each field. This will serve as a guide when we create variables for the dialogs used to collect the data that will then be added to the table.

The object is to create a master repeating dialog (never displayed to the user), which we will call "Data Table," containing all of the data table field variables we require. The variables could have generic names like:

•	FirstName-t
•	MiddleName-t
•	LastName-t
•	Suffix-t
•	FullName-t (computed from first, middle, last, suffix)
•	Gender-m
•	DateOfBirth-d
•	etc.
(Under Advanced Options for these variables, it's a good idea to check "Ask Only in Dialog" and "Don't Warn If Unanswered.")

We will also create an index number field (Index-n) to identify each record, and a numeric counter variable (DataTableCounter-n) that we can use to assign and keep track of the sequential index numbers.

For each dialog we create to collect personal data, we will create a corresponding computation to add the data to the master table. For example:

REPEAT Client's Children
   SET DataTableCounter-n TO DataTableCounter-n + 1
   SET Index-n[DataTableCounter-n] TO DataTableCounter-n
   SET FirstName-t[DataTableCounter-n] TO ChildFirstName-t
   SET MiddleName-t[DataTableCounter-n] TO ChildMiddleName-t
   ... etc.
END REPEAT
Note here that although the data table field variables are not actually on the "Client's Children" dialog, HotDocs allows you to copy values to "Data Table" field variables, effectively creating a "Data Table" on the fly.

As an alternative to collecting data through a series of separate dialogs, we could also present the user with one master "names interview" at the beginning of assembly. Using this method, the user is prompted to input all information about every person needed in the documents without respect to the person's role. This information is placed into the "Data Table" dialog using the same type of computation as above.

That takes care of constructing Data Table; now how do we allow the user to select more than one record on a dialog? For each selection to be made, we need to generate a multiple choice variable where the options consist of the index number followed by names taken from our Data Table:

ASK NONE
REPEAT Data Table
   ASCEND LastName-t  //to sort the list by last name
   SET Temp-t TO FORMAT( Index-n, "09" ) + "     " + FullName-t
   ADD Temp-t TO SuccessorTrustee1-m
   ADD Temp-t TO SuccessorTrustee2-m
   ADD Temp-t TO meSuccessorTrustee3
   ... etc.
END REPEAT
ASK DEFAULT
(Note: The ASK commands prevent the data table from popping up during assembly.) So the mc options might look like this:

11   John Adams
06   Susan Adams
08   Larry Boone
Formatting the index number as "09" (which produces 01, 02, etc.) allows the names to line up properly, and moreover when we need to pull the index number out later we can simply grab the first two characters. (Note: if you anticipate your list may exceed 99 items, you should format your numbers as "009".)

Note also that it would be easy to filter the data table to create lists that are more specific.

These mc variables can then be placed on repeating or regular dialogs to allow the user to make selections (dropdown lists work handily and save space on the dialog). You can put as many of the mc variables on a dialog as you want, which solves the pick list limitation of one per dialog. Bear in mind, however, that whereas pick lists allow users to add data records at the same time as they are making selections, you would not be able to do that here - all the data pertaining to the selections for a particular dialog must be collected before the choices are presented to the user.

After the user makes selections, we extract the index numbers like this:

REPEAT Successor Trustees
   SET SuccessorTrustee1-n TO FIRST( SuccessorTrustee1-m, 2 )
   SET SuccessorTrustee2-n TO FIRST( SuccessorTrustee2-m, 2 )
   SET SuccessorTrustee3-n TO FIRST( SuccessorTrustee3-m, 2 )
END REPEAT
where SuccessorTrustee1-n is a number variable the purpose of which is to hold the index number of the name selected (conveniently, HotDocs converts an mc text value such as "01" to the numeric value "1"). The number variables must be placed on the dialogs also, but since we want the user to see the mc variables only, we can use dialog script commands to HIDE the number variables.

Finally, to allow the template to access the various "data fields" according to the user's selections, we insert variables into the template in the following format:

"If for any reason any one of «FullName-t[SuccessorTrustee1-n]:LIKE THIS», «FullName-t[SuccessorTrustee2-n]:LIKE THIS» and «FullName-t[SuccessorTrustee3-n]:LIKE THIS» fails or ceases to act, ... "
This may look a little strange, but what's happening is that the user's mc selection provides an index number that hooks into the master data table, which in turn allows us to access an unlimited number of data field values for that person (not to mention the fact that we don't have to create a proliferation of data variables). For example, we can use any of the following variables:

«Gender-m[SuccessorTrustee1-n]:he/she»
«DateOfBirth-d[SuccessorTrustee1-n]:June 3, 1990»
«CountyOfResidence-t[SuccessorTrustee1-n]»
etc.
Note: While HotDocs has no trouble interpreting «VarName[Index]», unfortunately it provides no easy method of inserting variables of that form into templates. However, you could use the computation creation dialog box as a scratch pad to create the variable using HotDocs' drag and drop features, and then cut and paste the result into the template. (Note that typing "<<" or ">>" in the computation editor automatically produces the appropriate chevron.) If you wish you may color the text between the chevrons blue, but this step is optional, and if you do you should not color the chevrons themselves (doing so will leave the color behind after assembly).

IMPORTANT: Be aware that if you revamp an existing system according to this schema, you should have a strategy for converting values from previous answer files to the new system so that no information will be lost.

105. Internal Database Tables - An Alternative to Pick Lists

How to emulate a database table without using pick lists or external databases; how to select multiple records on a single dialog; how to associate two or more different lists with a particular dialog.

HotDocs does not provide a date format that includes and in the year, nor is it possible to create a custom format that includes and. Much less does HotDocs provide a date format that includes in the year of our Lord, a necessary construction in some locales. This computation provides a way of doing it.

The computation only uses two variables, DateVar, the date variable you wish to format, and Temp-n, a temporary number variable (set its Advanced options to "Ask only in dialog," "Don't warn if unanswered," and "Don't save in answer file").

We first take the month and day values formatted as needed, then include the text "in the year of our Lord, this".

The year must be taken in segments, as the thousands and ones values need to be fomatted differently than the hundreds and tens. To isolate just the thousands, we divide the year by 1000 and trim off everything after the decimal point, then multiply by 1000. For example: 1999 / 1000 = 1.999; 1 * 1000 = 1000. To eliminate the thousands position from the year, we can subtract the truncated value from the original value: 1999 - 1000 = 999. This same technique is used to isolate and format the hundreds, tens and ones.

104. "In the year of our Lord ..."

Spell out a date in the format "Third day of June in the year of our Lord, this One Thousandth Nine Hundred and Ninety Ninth".

HotDocs does not provide a date format that includes and in the year, nor is it possible to create a custom format that includes and. This computation provides a way of doing it.

The computation only uses two variables, DateVar, the date variable you wish to format, and Temp-n, a temporary number variable (set its Advanced options to "Ask only in dialog," "Don't warn if unanswered," and "Don't save in answer file").

To insert the word and inside of the year, we first take only the thousands and hundreds values of the year and format them, then we insert our and and finally add on the tens and ones values of the year.

103. Include "and" in the Year

Spell out a date in the format "Third day of June, One Thousand Nine Hundred and Ninety".

The simplest way to perform time calculations is to first convert the hours value to military time (00:00 for 12:00 am, 13:00 for 1:00 pm, 23:00 for 11:00 pm). This calculation demonstrates how to do this.

Variables:

•	Hour-n - A number variable containing the hours value.
•	Min-n - A number variable containing the minutes value.
•	AmPm-m - A multiple-choice variable the user can use to select am or pm.
This computation assumes that you have stored hours and minutes in separate number variables. If your time value is in a text variable, you should use Computation 99: Parsing Time Values.

To make the conversion, we first check AmPm-m to see whether Hour-n is an am or pm value. If the time is am and Hour-n is 12, we will need to change the Hour-n variable to 0. If the time is pm and Hour-n is 1-11, we will need to add 12 hours to the Hour-n variable.

With the hours converted to military time, you can now do time calculations such as Computation #0100: Elapsed Time, and Computation #0101: Total Time.

102. Convert Hours to Military Time

Convert hours to military time (00:00 for 12:00 am, 13:00 for 1:00 pm, 23:00 for 11:00 pm, etc.).

This computation totals time entries from either a repeated dialog or from a list. The calculated hours and minutes values are placed in number variables, and a nicely formatted string is also returned.

Variables: The computation assumes the following variables:

•	Hours-n - A number variable which holds the number of hours for a single time entry.
•	Mins-n - A number variable which holds the number of minutes for a single time entry.
•	TotalHours-n - A number variable which holds the total hours computed from the time entries.
•	TotalMins-n - A number variable which holds the total minutes computed from the time entries.
•	Time Entries - A repeated dialog box which contains two variables, Hours-n and Mins-n.

Elapsed Time: This computation assumes that you already know the elapsed time for each time entry. If, however, your time entries simply have a start time and and end time, you will need to compute the elapsed time as well. Computation #0100: Elapsed Time shows how to do this. You would include the elapsed time calculation within the REPEAT where shown.

The computation should be quite straightforward. We run through the REPEAT, adding each Hours-n and Mins-n value into TotalHours-n and TotalMins-n. Note that we use the ZERO model to give unanswered variables a value of 0. Once we have summed all of the time entries, the TotalMins-n variable will likely have a value much greater than 60. These extra minutes should be converted into hours. We add one hour to TotalHours-n for every 60 minutes in TotalMinutes-n, then set TotalMinutes-n to the REMAINDER.

101. Total Time

Total the time entries from a list or a repeated dialog.

This computation takes a begin time and an end time and calculates the amount of time elapsed between them in hours and minutes. Days are optional. The calculated days, hours and minutes are placed in number variables, and a nicely formatted string is also returned.

Variables: The computation assumes the following variables:

•	DayStart-n (Optional) - A date variable which holds the start date.
•	HourStart-n - A number variable which holds the start hour.
•	MinStart-n - A number variable which holds the start minute.
•	DayEnd-n (Optional) - A date variable which holds the end date.
•	HourEnd-n - A number variable which holds the end hour.
•	MinEnd-n - A number variable which holds the end minute.
•	Days-n (Optional) - A number variable which will be set to the number of elapsed days.
•	Hours-n - A number variable which will be set to the number of elapsed hours.
•	Minutes-n - A number variable which will be set to the number of elapsed minutes.

Preparing the Variables: Before you can do time calculations, you must make sure that the hours and minutes are placed in separate number variables, and that the hours have been converted into military time. If your time value is in a text variable, you should use Computation 99: Parsing Time Values. Use Computation #0102: Convert Hours to Military Time if your hours value needs to be converted to military time.

Days: Elapsed days are optional. To exclude days from the calculation, remove the first section of the computation and the two IF ... END IF blocks marked for removal.

Hours: As long as the hours are in military time, we can arrive at elapsed hours by subtracting HourStart-n from HourEnd-n. If this results in a negative number, we reduce the Days-n variable by one day and add 24 hours.

Minutes: Like hours, we arrive at elapsed minutes by subtracting MinStart-n from MinEnd-n. If this results in a negative number, we reduce the Hours-n variable by one hour and add 60 minutes to Days-n.

Caveat: If your start time is later than your end time, you'll get inaccurate results. That should go without saying, but there is always someone ...

100. Elapsed Time

Compute elapsed time in days (optional), hours, and minutes.

Before you can do time calculations, you must get the hours and minutes into separate number variables. Ideally you would have the user input these values directly into number variables, but it may be that the time value is in a text variable. This computation will extract a time value from a text variable and place the hours (as military time) and minutes into number variables. This computation assumes that the time is in the format Hours:Minutes am/pm, with no other text in the string. Leading zeros are not necessary (i.e. both 02:00 and 2:00 are fine).

Variables: The computation assumes the following variables:

•	TextVar - The text variable containing the time value.
•	Hour-n - A number variable which will be set to the hours value.
•	Min-n - A number variable which will be set to the minutes value.
•	Temp-n - A temporary number variable.

Hours: Assuming that the first item in the string is the hours value, we can extract it by simply using the INTEGER model, which takes every character up to the first non-numeric character and converts it to an integer value. We then place this value in our Hour-n variable.

AM/PM: The easiest way to deal with am/pm in time computations is to simply make sure that the hours are in military time (00:00 for 12:00 am, 13:00 for 1:00 pm, 23:00 for 11:00 pm). The quickest way to find whether the time in TextVar is am or pm is to use the CONTAINS model, which looks to see if a string contains a given character or short string. TextVar CONTAINS "pm" will quickly tell us whether the time value in TextVar is am or pm. If the time is am and the hour is 12, we will need to change the Hour-n variable to 0. If the time is pm and the hour is 1-11, we will need to add 12 hours to the Hour-n variable.

Minutes: To extract the minutes from the time value, we first need to find the position of the colon ":" in the time string. We set this position in the temporary number variable Temp-n for easy reference. Once we know where the colon is, we can again use the INTEGER model to extract the integer value of everything after the colon. This value is then placed in the Min-n variable.

Time Calculations: With the hours and minutes now placed in the Hour-n and Min-n variables, you can do time calculations such as Computation #0100: Elapsed Time, and Computation #0101: Total Time.

99. Parsing Time Values

Parse hours, minutes, and am/pm from a text string and SET them in number variables for time calculations

Custom fields in Amicus Attorney present a problem when exported to HotDocs: All of the custom fields are text values, even date, number, and true/false fields. The Amicus date, number, and true/false options only affect the way the data is formatted/displayed in Amicus. They do not create true date, number, or true/false values. This means that custom Amicus fields cannot be mapped directly to HotDocs date, number, or true/false variables. They must first be converted to HotDocs date, number, or true/false values.

NOTE: This applies only to custom fields in Amicus. All predefined Amicus fields export properly as true text, date, number, and true/false values.

Date Fields. Amicus exports custom date fields as DD MM YYYY. For example, the Fourth of July, 2001 would be exported as 04 07 2001. This makes conversion easy. We can extract the first two characters as the day, characters 4 & 5 as the month, and the last four characters as the year. Because these are still text values (even though they are digits), we must use the INTEGER model to convert them to integers. We can then plug these three integer values into the DATE OF( day, month, year ) model to obtain a valid HotDocs date value. The computation will return this date value, or you can SET a date variable to this value.

Number Fields. Amicus exports custom number fields as a string of digits without any separating punctuation except for a decimal point. So 3,000 would be exported as 3000, and 2,500.75 as 2500.75. Using the INTEGER model we can easily obtain an integer value of everything up to the decimal place. But if there is a decimal value, it will need to be extracted manually and added on.

Extracting the decimal value requires two temporary variables, Temp-n, a number variable, and Temp-t, a text variable (be sure to set their Advanced options to "Don't warn if unanswered," "Ask only in dialog," and "Don't save in answer file").

To extract the decimal value, we first look to see what the string position of the decimal is with the POSITION model, and SET this value in Temp-n. Next we take all of the characters in the Amicus custom field from this character position forward with the LAST model, and SET Temp-t to this string. We then need to convert this string to an integer value with the INTEGER model. At this point we have a non-decimal integer. For example, if the decimal value was .25, we now have an integer value of 25. To convert this to a decimal value, we must divide by some power of 10: 10 for a decimal value one digit long, 100 for a decimal value two digits long, etc. We can do this by using the POWER model to obtain a value of 10 to the power of X, where X is the character length of the decimal string. We divide our integer by this value to make it a decimal, and add the resulting decimal value to our RESULT.

A HotDocs number value is returned. You can also SET a number variable to this value if you wish.

True/False Fields. Amicus exports custom true/false fields as simply "TRUE" or "FALSE" (text values). This makes it easy to convert the custom field to a HotDocs True/False value. The example above shows how it is done. The computation will return either TRUE or FALSE. It can also be made to SET a True/False variable to TRUE or FALSE.

98. Amicus Attorney Custom Fields

How to convert an Amicus Attorney custom date, number, or true/false field into one usable by HotDocs.

bottom of page