Permalink
Fetching contributors…
Cannot retrieve contributors at this time
653 lines (622 sloc) 21.1 KB
---
metadata:
description: |
This question file contains questions that are common in
law-related interviews. It also imports docassemble functions,
initializes a role system involving a "client" and an "advocate,"
and defines objects including "client," "advocate," "case,"
"spouse," "pleading," and "court."
authors:
- name: Jonathan Pyle
organization: none
revision_date: 2017-05-26
comment: |
A "metadata" block contains information about the interview, such as
the title of the interview as displayed in the navigation bar.
---
modules:
- docassemble.base.legal
comment: |
A "modules" section imports class names and function names from
Python modules. The docassemble.base.legal module defines some
object classes and functions that are useful in legal applications.
Using docassemble.base.legal in "modules" also has the effect of
importing all of the class names and function names that are in
docassemble.base.util. So you never need to include both
docassemble.base.legal and docassemble.base.util together in the
same "modules" block.
---
default role: client
code: |
if user_logged_in() and user_has_privilege('advocate'):
user = advocate
role = 'advocate'
else:
user = client
role = 'client'
set_info(user=user, role=role)
comment: |
This is a special "initial block" that initializes the "roles" system
for the interview. (This is an advanced feature.)
The default user role is "client" and a secondary role is
"advocate." Unless modified with a "role" directive, all questions
will require the user to be a "client." The user is assumed to have
the role of "advocate" role in this interview if the user is logged
in and the user has "advocate" as one of his or her user roles.
Many docassemble functions and methods need to know who the user is.
The set_info() function communicates that information to the
docassemble code.
Since the code here is paired with the "default role" declaration,
it is run as "initial" code, meaning that it is run every time
docassemble processes the interview (i.e., every time the screen
loads). This is important because in a multi-user interview, a
"client" and an "advocate" could be interacting with the same
interview with the same dictionary of variables at the same time.
But they would need to see different things, so it isn't enough just
to use a variable in the interview to keep track of the current
user; this needs to be reconsidered every time the screen loads.
---
event: role_event
question: You are done for now.
subquestion: |
% if 'advocate' in role_needed:
An advocate needs to review your answers before you can proceed.
Please remember the following link and come back to it when you
receive notice to do so:
[${ interview_url() }](${ interview_url() })
% else:
Thanks, the client needs to resume the interview now.
% endif
decoration: exit
buttons:
- Exit: leave
comment: |
This block is related to the "roles" system that was initialized in
the previous block. (This is an advanced feature.)
When docassemble needs to ask a question that requires a role other
than the role of the current user, it needs to display a special
message for the user. It does this by searching for a question that
offers to define the variable "role_event," and displaying that
question. The question above is an example of such a question. It
will be displayed in the event of a "role change" because it
contains the directive "event: role_event."
---
objects:
- case: Case
- client: Individual
- spouse: Individual
- advocate: Individual
- pleading: LegalFiling
- court: Court
comment: |
An "objects" section initializes variables that are docassemble
objects. The object types here (Case, Individual, LegalFiling, and
Court) are imported through the docassemble.base.legal module.
(See the "modules" block above.)
---
generic object: Individual
sets: x.child
code: |
x.initializeAttribute('child', ChildList)
---
generic object: Individual
sets: x.income
code: |
x.initializeAttribute('income', Income)
---
generic object: Individual
sets: x.asset
code: |
x.initializeAttribute('asset', Asset)
---
generic object: Individual
sets: x.expense
code: |
x.initializeAttribute('expense', Expense)
---
mandatory: true
code: |
case.court = court
pleading.case = case
comment: |
This code defines some basic relations among the objects created in
the objects block of this YAML file.
The objects created by the `objects` block do not have any
connections among themselves, initially. The interview needs to
make those connections. This "mandatory" code block establishes
those connections.
These connections among objects are what allows you to write things
like pleading.caption(). In order to write the caption for a
pleading, it is necessary to know the case of which the pleading is
a part and the court in which the case is filed. The ".caption()"
method only has access to the attributes of "pleading," but these
connections allow the ".caption()" method to gain access to the case
and the court.
---
image sets:
freepik:
attribution: |
Icon made by [Freepik](http://www.flaticon.com/authors/freepik)
images:
bills: money146.svg
children: children2.svg
finishline: checkered12.svg
gavel: court.svg
gaveljudge: magistrate.svg
home: home168.svg
piggybank: savings1.svg
scalesofjustice: judge1.svg
stocks: increasing10.svg
wallet: commerce.svg
document: contract11.svg
calendar: calendar146.svg
picture: picture64.svg
parentchild: man32.svg
coins: coins36.svg
exit: open203.svg
man: silhouette21.svg
person: silhouette21.svg
woman: women13.svg
girl: girl4.svg
male: male244.svg
female: female243.svg
map: map32.svg
comment: |
Here we define some icons for inclusion as decorations or emoji.
These files are located in the docassemble.base package in the
subdirectory docassemble/base/data/static.
---
generic object: Individual
question: |
What is ${ x.possessive('date of birth') }?
fields:
- Date of Birth: x.birthdate
datatype: date
comment: |
This question file defines a number of "generic" questions like
these. If your interview refers to a variable called user.birthdate,
docassemble will first look for a question that sets "user.birthdate"
specifically, but if it does not find it, it will look for a
question for which the generic object property is set to the object
type of the user object, which is Individual, and where the question
offers to set the variable x.birthdate.
It will find that question here.
The question uses the possessive() method, which is a method of the
Individual class. The result is that the question will be "What is
your date of birth?" if x is the user, but will otherwise ask "What
is Jane Doe's date of birth?"
By using "generic" questions, you can write a single question that
works in a variety of circumstances. This saves you from having to
write multiple questions, and also helps ensure that if you want to
make a global change to the way a question is asked, you can do so
in one place.
If you ever want to use a more specific question for a specific
variable, you can. For example, if your code calls for
spouse.birthdate, you may to ask the question in a different way.
(E.g., "What is the birthdate of your lovely spouse? If you don't
know this, you are in deep trouble!") You would do this by defining
a non-generic question that sets spouse.birthdate, in which case
docassemble would use that question instead of the generic question.
---
generic object: Individual
question: |
What is ${ x.possessive('time zone') }?
fields:
- Time Zone: x.timezone
code: timezone_list()
---
generic object: Individual
question: |
What is ${ x.possessive('Social Security Number') }?
fields:
- Social Security Number: x.ssn
---
generic object: Individual
question: |
${ x.is_are_you(capitalize=True) } a defendant in this case?
yesno: x.is_defendant
---
generic object: Individual
field: x.marital_status
question: |
What is ${ x.possessive('marital status') }?
choices:
- Married: Married
- Single: Single
- Divorced: Divorced
- Separated: Separated
comment: |
This is an example of a multiple-choice question. Each of the
choices can be a key/value pair, or it can be a single text item.
If the choice is a key/value pair, the key is the label that is
shown to the user and value is the value to which the variable will
be set.
---
field: user_understands_how_to_use_signature_feature
question: Instructions for signing your name
subquestion: |
On the next screen, you will see a box in which you can sign your
name using your mouse, track pad, or touch screen. If you make a
mistake, you can press "Clear" and try again. For best results, try
signing your name *slowly*.
---
generic object: Individual
question: |
Sign your name
signature: x.signature
need:
- x.name.first
- user_understands_how_to_use_signature_feature
under: |
${ x.name }
comment: |
docassemble can collect signatures from users, who can write their
signature with their finger on a touchscreen device, or use a mouse
or trackpad. The signatures can be added to documents.
---
template: blank_signature
content: |
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
comment: |
This template can be used to insert into a document a blank line
that someone might sign.
---
template: empty_signature
content: |
\_\_\_[Your signature here]\_\_\_
comment: |
This template can be used in place of a user's signature. It is a
good practice to show users where their signature would go on a
document before asking the user for his or her signature.
---
generic object: Individual
question: |
Is this ${ x.possessive('signature') }?
subquestion: |
${ x.signature.show() }
field: x.signature_verified_button
buttons:
- Yes: True
- No: False
- Let me try again: Null
---
generic object: Individual
code: |
if x.signature_verified_button in (True, False):
x.signature_verified = x.signature_verified_button
else:
force_ask('x.signature', 'x.signature_verified_button')
---
generic object: Individual
question: |
${ x.is_are_you(capitalize=True) } a citizen of the United States?
yesno: x.is_citizen
---
field: user_understands_no_attorney_client_relationship
question: |
Your use of this system does not mean that you have a lawyer. Do
you understand this?
buttons:
- "I understand": understands
- code: |
[{'does not understand':"I do not understand"}, {'unsure':"I'm not sure"}]
comment: |
You can specify whether you want multiple choices to appear as
buttons by using the word "buttons" instead of the word "choices."
Also, the example above shows how you can use Python code to
generate the selections of multiple-choice question. The code is
evaluated at the time the question is asked.
---
generic object: Individual
question: |
What is ${ x.possessive('e-mail address') }?
fields:
- E-mail: x.email
datatype: email
comment: |
The datatype "email" presents a text box that is like ordinary text
boxes except that validation is applied that checks to make sure the
e-mail address is valid. Also, on supporting mobile web browsers,
there is a different keyboard option (e.g, the @ sign is readily
available).
---
generic object: Individual
question: |
What is ${ x.possessive('gender') }?
field: x.gender
choices:
- Male: male
- Female: female
- Other: other
---
generic object: Individual
question: |
What is ${ x.object_possessive('name') }?
fields:
- First Name: x.name.first
default: ${ x.first_name_hint() }
- Middle Name: x.name.middle
required: False
- Last Name: x.name.last
default: ${ x.last_name_hint() }
- Suffix: x.name.suffix
required: False
code: |
name_suffix()
comment: |
If an object does not have a name yet, generic questions can refer
to it by the name of the variable itself, using the method
.object_possessive(). For example, suppose you create an object,
case.judge, with the class of Individual. If the name of case.judge
is ever needed, docassemble will use the question above to ask "What
is the name of the judge in the case?" If the object is called
user, it will ask "What is your name?" If the object is called
village_idiot, it will ask "What is the village idiot's name?"
---
generic list object: Individual
question: |
What is the name of the ${ x[i].object_name() }?
fields:
- First Name: x[i].name.first
- Middle Name: x[i].name.middle
required: False
- Last Name: x[i].name.last
- Suffix: x[i].name.suffix
required: False
code: |
name_suffix()
comment: |
Generic questions can also use indices, for example to fill out the
names of a list of people. (E.g., case.plaintiff.)
This example also illustrates how the author can control whether the
user can leave a field blank. By default, all fields are required,
but the author can add required: False to a field to indicate that
the field can be left blank.
---
generic list object: Individual
question: |
What is ${ x.possessive(ordinal(i) + " child") }'s name?
fields:
- Somebody already mentioned: x.child[i]
datatype: object
disable others: True
choices: case.all_known_people()
exclude:
- x
- x.child
- First Name: x.child[i].name.first
- Middle Name: x.child[i].name.middle
required: False
- Last Name: x.child[i].name.last
default: ${ x.name.last }
- Suffix: x.child[i].name.suffix
required: False
code: |
name_suffix()
comment: |
This illustrates the use of the ".possessive()" method of the class
Individual. Depending on who x is, this question will ask different
things:
Example 1: What is your second child's name?
Example 2: What is John Doe's first child's name?
---
generic object: DAList
question: |
Are there any ${ x.as_noun(plural=True) }?
yesno: x.there_are_any
comment: |
The attributes .there_are_any and .there_is_another are special
attributes that are used in the gathering of "groups" of things
in docassemble interviews.
---
generic object: Individual
question: |
${ x.do_question('have', capitalize=True) } any children?
yesno: x.child.there_are_any
decoration: children
comment: |
This illustrates the use of the ".do_question()" method of the class
Individual. Depending on who x is, this question will ask different
things:
Example 1: Do you have any children?
Example 2: Does Jane Doe have any children?
---
generic object: DAList
question: |
You have told me that there ${ x.does_verb("is") }
${ x.number_as_word() } ${ x.as_noun() }, ${ x }.
Is there another ${ x.as_singular_noun() }?
yesno: x.there_is_another
comment: |
It is possible to write highly generalized "generic" questions that
use functions that ask questions of users based on variable names
and linguistic variations of variable names. For that reason, it is
a good practice to give your variables meaningful, plain-English
names.
For example, if you create a PartyList called "plaintiff," this
generic question will ask something like: "You have told me that
there is one plaintiff, John Smith. Is there another plaintiff?"
This would not be possible if your variable name was something that
only made sense to you, like "bad_guys_list_two."
---
generic object: Individual
question: |
So far, you have told me about
${ x.possessive(x.child.number_as_word()) }
${ x.child.as_noun() }, ${ x.child }.
${ x.do_question('have', capitalize=True) } any other children?
yesno: x.child.there_is_another
decoration: children
comment: |
This also illustrates the use of various methods of the class Individual.
Depending on who x is, this question will ask different things:
Example 1: So far, you have told me about John Doe's two children,
Sally Doe and Harold Doe. Does John Doe have any other children?
Example 2: So far, you have told me about your one child, Kathleen
Smith. Do you have any other children?
---
generic object: Individual
question: |
${ x.is_are_you(capitalize=True) } a plaintiff in this case?
subquestion: |
A "plaintiff" is a person who starts a case by filing a lawsuit
against a person called a "defendant." Plaintiffs and defendants
are the "parties" in a case.
decoration: scalesofjustice
yesno: x.is_plaintiff
---
generic object: Individual
question: |
Where ${ x.do_question('live') } in
${ state_name(case.state) }?
fields:
- Address: x.address.address
- Unit: x.address.unit
required: False
help: The apartment, suite, or unit number of the residence.
- City: x.address.city
- State: x.address.state
default:
code: |
case.state
code: |
us.states.mapping('abbr', 'name')
- Zip: x.address.zip
required: False
---
generic object: Address
question: |
In which county is
${ x.on_one_line() }
located?
fields:
- County: x.county
---
generic object: Address
sets: x.county
code: |
x.geolocate()
comment: |
This code block and the question before it illustrate the concept
of "fallback" questions. If the interview needs the "county"
attribute of an address, but finds that it is not defined, it will
first run this code block, which "geolocates" the address. That is,
it goes on to the internet and runs the address through a
geolocation service, which returns geographic information about the
address.
This code block uses the "sets" directive to indicate that the code
block offers sets the attribute "county." Normally, you don't have
to use "sets" with code blocks because docassemble can see by
looking at the code what variables the code will set. In the case
of the code "x.geolocate()," however, it is not apparent that the
code is offering to set the "county" attribute. Therefore we need
to manually specify what the code block is offering to do.
It is significant that the code block merely "offers" to set these
variables. The "x.geolocate()" code might fail. The user might put
in an address that the geolocation service does not understand. Or
the geolocation service might be down at the time. If that happens,
the code block will run, but the attributes will not be set.
If the variable that a code block offers to set is not actually set
when the code is run, docassemble will look for another block that
offers to set the variables. In the case of the "county" attribute
of an address, the question immediately preceding this one offers to
set the "county" attribute. It does so by asking the user a
question, rather than by using a geolocation service. This question
serves as a "fallback" question.
Note that when docassemble looks for a block that offers to set a
variable, it starts at the end of the interview and proceeds
backward. Therefore, the order in which these blocks appear in
the [YAML] file is significant.
---
generic object: City
question: |
In which county in
${ state_name(x.state) }
is
${ x.city }
located?
fields:
- County: x.county
hint: |
e.g., Springfield County
---
generic object: City
sets: x.county
code: |
x.geolocate()
comment: |
Suppose you have an object "birthplace" of type "City." A "City"
object is a subtype of an "Address," and an "Address" is a type of
"DAObject." If your interview needs a definition of
birthplace.county, docassemble will first look for blocks that offer
to define "birthplace.county," then for "generic object: City"
blocks that offer to define "x.county," then for "generic object:
Address" blocks that offer to define "x.county," then for "generic
object: DAObject" blocks that offer to define "x.county."
Therefore, the "generic object: Address" code block is capable of
defining "birthplace.county." However, if we wish to have a
fallback question that is "City"-specific, and we tag it with
"generic object: City," this question will take priority over the
"generic object: Address" code block.
Therefore, in order to have a "City"-specific fallback question, we
also need a "City"-specific code block.
---
generic object: Document
question: |
Are you able to attach or take a picture of ${ x.title }?
yesno: x.able_to_attach
---
generic object: Document
question: |
Please attach or take a picture of ${ x.title }.
fields:
- label: |
${ capitalize(x.title) }
field: x.file
datatype: file
comment: |
These two questions facilitate using the "Document" object type to
gather uploaded documents if the user is able to upload the document.
---
generic object: Individual
question: |
In what country ${ x.do_question('live') }?
fields:
- Country: x.address.country
---
generic object: Individual
question: |
In what neighborhood ${ x.do_question('live') }?
fields:
- Neighborhood: x.address.neighborhood
---
generic object: Individual
question: |
In what county ${ x.do_question('live') }?
fields:
- County: x.address.county
---
generic object: Address
sets:
- x.county
- x.country
- x.neighborhood
code: |
x.geolocate()
comment: |
---
generic object: DAList
code: |
x.gather()
x.re_gathered = True
---
generic object: DADict
code: |
x.gather()
x.re_gathered = True
---
generic object: DASet
code: |
x.gather()
x.re_gathered = True
...