docassemble.AssemblyLine 4.0.0__tar.gz → 4.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. {docassemble_assemblyline-4.0.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-4.1.0}/PKG-INFO +2 -2
  2. docassemble_assemblyline-4.1.0/docassemble/AssemblyLine/__init__.py +1 -0
  3. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/al_general.py +39 -1
  4. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/custom_jinja_filters.py +112 -2
  5. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +39 -4
  6. docassemble_assemblyline-4.1.0/docassemble/AssemblyLine/data/questions/test_if_final.yml +27 -0
  7. docassemble_assemblyline-4.1.0/docassemble/AssemblyLine/data/templates/test_if_final.docx +0 -0
  8. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/sessions.py +34 -40
  9. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +2 -2
  10. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +3 -1
  11. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble.AssemblyLine.egg-info/requires.txt +1 -1
  12. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/setup.py +2 -2
  13. docassemble_assemblyline-4.0.0/docassemble/AssemblyLine/__init__.py +0 -1
  14. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/LICENSE +0 -0
  15. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/MANIFEST.in +0 -0
  16. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/README.md +0 -0
  17. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/al_courts.py +0 -0
  18. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/al_document.py +0 -0
  19. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
  20. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_document.yml +0 -0
  21. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
  22. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
  23. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
  24. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
  25. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
  26. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
  27. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
  28. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
  29. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
  30. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +0 -0
  31. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
  32. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
  33. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
  34. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
  35. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +0 -0
  36. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
  37. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/ql_namechange.yml +0 -0
  38. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
  39. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
  40. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
  41. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
  42. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
  43. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +0 -0
  44. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
  45. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
  46. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
  47. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_catchall.yml +0 -0
  48. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
  49. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_preferred_formats.yml +0 -0
  50. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
  51. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/questions/test_signature.yml +0 -0
  52. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
  53. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
  54. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
  55. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
  56. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
  57. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
  58. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
  59. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
  60. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
  61. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  62. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
  63. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
  64. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
  65. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
  66. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
  67. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
  68. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
  69. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
  70. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
  71. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
  72. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
  73. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
  74. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
  75. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
  76. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
  77. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
  78. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
  79. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
  80. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
  81. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
  82. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
  83. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
  84. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/data/templates/test_catchall.docx +0 -0
  85. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/language.py +0 -0
  86. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/py.typed +0 -0
  87. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/requirements.txt +0 -0
  88. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/sign.py +0 -0
  89. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
  90. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/test_al_general.py +0 -0
  91. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/AssemblyLine/test_language.py +0 -0
  92. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble/__init__.py +0 -0
  93. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
  94. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
  95. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
  96. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/pyproject.toml +0 -0
  97. {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.1.0}/setup.cfg +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 4.0.0
3
+ Version: 4.1.0
4
4
  Home-page: https://courtformsonline.org
5
5
  Author: Suffolk Legal Innovation and Technology Lab
6
6
  Author-email: qsteenhuis@suffolk.edu
7
7
  License: The MIT License (MIT)
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: docassemble.ALToolbox>=0.11.1
10
+ Requires-Dist: docassemble.ALToolbox>=0.12.0
11
11
  Requires-Dist: docassemble.GithubFeedbackForm>=0.4.1.1
12
12
  Dynamic: author
13
13
  Dynamic: author-email
@@ -0,0 +1 @@
1
+ __version__ = '4.1.0'
@@ -958,6 +958,14 @@ class ALIndividual(Individual):
958
958
  ) -> str:
959
959
  """Fetches and formats the phone numbers of the individual.
960
960
 
961
+ Supports the following attributes:
962
+
963
+ - `mobile_number`: Mobile phone number
964
+ - `phone_number`: Other phone number
965
+ - `work_number`: Work phone number
966
+ - `other_number`: Any other phone number
967
+ - `home_number`: Home phone number (if applicable)
968
+
961
969
  Args:
962
970
  country (str, optional): The country for phone number formatting. Defaults to the country of the docassemble server.
963
971
  show_impounded (bool): If True, shows the phone numbers even if impounded. Defaults to False.
@@ -986,6 +994,36 @@ class ALIndividual(Individual):
986
994
  nums.append({fmt_number: "other"})
987
995
  else:
988
996
  nums.append({self.phone_number: "other"})
997
+ if hasattr(self, "work_number") and self.work_number:
998
+ fmt_number = None
999
+ try:
1000
+ fmt_number = phone_number_formatted(self.work_number, country=country)
1001
+ except:
1002
+ fmt_number = None
1003
+ if fmt_number:
1004
+ nums.append({fmt_number: "work"})
1005
+ else:
1006
+ nums.append({self.work_number: "work"})
1007
+ if hasattr(self, "other_number") and self.other_number:
1008
+ fmt_number = None
1009
+ try:
1010
+ fmt_number = phone_number_formatted(self.other_number, country=country)
1011
+ except:
1012
+ fmt_number = None
1013
+ if fmt_number:
1014
+ nums.append({fmt_number: "other"})
1015
+ else:
1016
+ nums.append({self.other_number: "other"})
1017
+ if hasattr(self, "home_number") and self.home_number:
1018
+ fmt_number = None
1019
+ try:
1020
+ fmt_number = phone_number_formatted(self.home_number, country=country)
1021
+ except:
1022
+ fmt_number = None
1023
+ if fmt_number:
1024
+ nums.append({fmt_number: "home"})
1025
+ else:
1026
+ nums.append({self.home_number: "home"})
989
1027
  if len(nums) < 1:
990
1028
  return ""
991
1029
  # Check for impounded phone number
@@ -2404,7 +2442,7 @@ def is_phone_or_email(text: str) -> bool:
2404
2442
  DAValidationError if the string is neither a valid phone number nor a valid email address.
2405
2443
  """
2406
2444
  sms_enabled = is_sms_enabled()
2407
- if re.match("\S+@\S+", text) or (sms_enabled and phone_number_is_valid(text)):
2445
+ if re.match(r"\S+@\S+", text) or (sms_enabled and phone_number_is_valid(text)):
2408
2446
  return True
2409
2447
  else:
2410
2448
  if sms_enabled:
@@ -5,8 +5,11 @@
5
5
 
6
6
  # See: https://docassemble.org/docs/documents.html#register_jinja_filter
7
7
 
8
- from typing import Any, Dict, List
9
- from docassemble.base.util import register_jinja_filter, DACatchAll
8
+ import re
9
+ from typing import Any, Dict, List, Optional, Union
10
+ from docassemble.base.util import register_jinja_filter, DACatchAll, word
11
+ from jinja2 import Undefined, pass_context
12
+ from jinja2.runtime import Context as Jinja2Context
10
13
 
11
14
  __all__ = [
12
15
  "catchall_options",
@@ -200,11 +203,118 @@ def catchall_subquestion(value: Any, subquestion: str) -> DACatchAll:
200
203
  return value
201
204
 
202
205
 
206
+ def _undefined_label(ud: Undefined) -> Union[str, None]:
207
+ """
208
+ Extract the variable name from a Jinja2 Undefined object for use as a placeholder label.
209
+
210
+ Args:
211
+ ud (Undefined): The Jinja2 Undefined object.
212
+ Returns:
213
+ str: A friendly name extracted from the Undefined object.
214
+ """
215
+ return getattr(ud, "_undefined_name", None)
216
+
217
+
218
+ @pass_context
219
+ def if_final(
220
+ context: Jinja2Context,
221
+ value: Any,
222
+ i: Optional[str] = None,
223
+ expected_i: Union[str, List[str]] = "final",
224
+ placeholder: Optional[str] = None,
225
+ ) -> Any:
226
+ """
227
+ Jinja2 filter to only seek the definition of a variable if the current value of `i`
228
+ is equal to the expected value (normally "final"); otherwise,
229
+ return a placeholder.
230
+
231
+ This is useful in ALDocument DOCX templates where you want to show a placeholder when
232
+ the document is being generated for preview or testing, but let Docassemble trigger
233
+ the actual value when the document is being generated for final output.
234
+
235
+ E.g., to show a placeholder for a signature field when the document is being
236
+ shown to the signer, but show the actual signature when the document is finalized.
237
+
238
+ The default placeholder is "[ signature ]" if the variable name follows the pattern "users[0].signature",
239
+ or [ variable_name ] if it is not an attribute of an item.
240
+
241
+ `i` will be the value from the template's context unless it is explicitly passed,
242
+ as in an ALDocument's "preview" or "final" values.
243
+
244
+ Example:
245
+ Contents of test_if_final.docx:
246
+ ```jinja
247
+ {{ users[0].signature | if_final }}
248
+ ```
249
+
250
+ Returns "[ signature ]" if `i` (passed to the context of the attachment block) is not "final",
251
+ otherwise the actual value of `users[0].signature`.
252
+
253
+ ```yaml
254
+ ---
255
+ include:
256
+ - assembly_line.yml
257
+ ---
258
+ mandatory: True
259
+ code: |
260
+ preview_screen
261
+ final_screen
262
+ ---
263
+ question: |
264
+ Here is what it looks like unsigned
265
+ subquestion: |
266
+ ${ test_if_final_attachment.as_pdf(key="preview") }
267
+ continue button field: preview_screen
268
+ ---
269
+ question: |
270
+ Here is what it looks like signed
271
+ subquestion: |
272
+ ${ test_if_final_attachment.as_pdf(key="final") }
273
+ event: final_screen
274
+ ---
275
+ objects:
276
+ - test_if_final_attachment: ALDocument.using(title="test_if_final", filename="test_if_final")
277
+ ---
278
+ attachment:
279
+ variable name: test_if_final_attachment[i]
280
+ docx template file: test_if_final.docx
281
+ ```
282
+
283
+ Args:
284
+ context (Jinja2Context): The Jinja2 context, automatically passed by the `pass_context` decorator.
285
+ value (Any): The original value as passed to the filter.
286
+ i (str, optional): The current value of `i`. If not provided, it will be fetched from the context.
287
+ expected_i (Union[str, List[str]], optional): The expected value(s) of `i` to trigger passthrough of `value`.
288
+ Defaults to "final".
289
+ placeholder (str, optional): The placeholder string to return if the condition is not met. If
290
+ not provided, a default placeholder will be generated based on the variable name.
291
+
292
+ Returns:
293
+ Any: The original `value` if `i` matches `expected_i`, otherwise the `placeholder`.
294
+ """
295
+ if i is None:
296
+ i = context.get("i")
297
+
298
+ if i != expected_i if isinstance(expected_i, str) else i not in expected_i:
299
+ if isinstance(value, Undefined):
300
+ _label = _undefined_label(value)
301
+ if _label and not placeholder:
302
+ if "." in _label:
303
+ _label = _label.split(".")[-1]
304
+ placeholder = f"[ {_label} ]"
305
+ return placeholder
306
+ return value
307
+
308
+ # Allow Docassemble to trap the UndefinedError when i == expected_i (e.g., "final" instead of "preview"), triggering a question to define `value`
309
+ return value
310
+
311
+
203
312
  register_jinja_filter("catchall_options", catchall_options)
204
313
  register_jinja_filter("catchall_label", catchall_label)
205
314
  register_jinja_filter("catchall_datatype", catchall_datatype)
206
315
  register_jinja_filter("catchall_question", catchall_question)
207
316
  register_jinja_filter("catchall_subquestion", catchall_subquestion)
317
+ register_jinja_filter("if_final", if_final)
208
318
 
209
319
 
210
320
  def catchall_fields_code(value: Any) -> List[Dict[str, Any]]:
@@ -1173,6 +1173,30 @@ fields:
1173
1173
  - Phone: x.mobile_number
1174
1174
  datatype: al_international_phone
1175
1175
  ---
1176
+ id: persons home number
1177
+ generic object: ALIndividual
1178
+ question: |
1179
+ What is ${x}'s home phone number?
1180
+ fields:
1181
+ - Phone: x.home_number
1182
+ datatype: al_international_phone
1183
+ ---
1184
+ id: persons work number
1185
+ generic object: ALIndividual
1186
+ question: |
1187
+ What is ${x}'s work phone number?
1188
+ fields:
1189
+ - Phone: x.work_number
1190
+ datatype: al_international_phone
1191
+ ---
1192
+ id: persons other number
1193
+ generic object: ALIndividual
1194
+ question: |
1195
+ What is ${x}'s other phone number?
1196
+ fields:
1197
+ - Phone: x.other_number
1198
+ datatype: al_international_phone
1199
+ ---
1176
1200
  id: persons fax number
1177
1201
  generic object: ALIndividual
1178
1202
  question: |
@@ -1440,6 +1464,17 @@ code: |
1440
1464
  code: |
1441
1465
  signature_fields = ['users[0].signature']
1442
1466
  ---
1467
+ code: |
1468
+ if len(signature_fields):
1469
+ if next(iter(signature_fields)).endswith(".signature"):
1470
+ # the id: signature choice question has to assume the object exists, so we don't guard against that here
1471
+ # note: this does not need to be an ALIndividual, so just use str() instead of .full_name()
1472
+ slash_s_example_name = str(value( next(iter(signature_fields))[:-len(".signature")] ))
1473
+ else:
1474
+ slash_s_example_name = "Signer's Name"
1475
+ else:
1476
+ slash_s_example_name = "Signer's Name"
1477
+ ---
1443
1478
  id: signature choice
1444
1479
  decoration: file-signature
1445
1480
  question: |
@@ -1458,7 +1493,7 @@ fields:
1458
1493
  We can share a link with your phone on the next screen
1459
1494
  % endif
1460
1495
  - On this device: this_device
1461
- - With a typed signature, like "${ al_typed_signature_prefix }${ users[0] }": typed_signature
1496
+ - With a typed signature, like "${ al_typed_signature_prefix }${ slash_s_example_name }": typed_signature
1462
1497
  show if:
1463
1498
  code: |
1464
1499
  al_form_requires_digital_signature and not (device() and (device().is_mobile or device().is_touch_capable))
@@ -1467,7 +1502,7 @@ fields:
1467
1502
  input type: radio
1468
1503
  choices:
1469
1504
  - On this device: this_device
1470
- - With a typed signature, like "${ al_typed_signature_prefix }${ users[0] }": typed_signature
1505
+ - With a typed signature, like "${ al_typed_signature_prefix }${ slash_s_example_name }": typed_signature
1471
1506
  show if:
1472
1507
  code: |
1473
1508
  al_form_requires_digital_signature and (device() and (device().is_mobile or device().is_touch_capable))
@@ -1483,7 +1518,7 @@ fields:
1483
1518
  We can share a link with your phone on the next screen
1484
1519
  % endif
1485
1520
  - On this device: this_device
1486
- - With a typed signature, like "${ al_typed_signature_prefix }${ users[0] }": typed_signature
1521
+ - With a typed signature, like "${ al_typed_signature_prefix }${ slash_s_example_name }": typed_signature
1487
1522
  - On the paper with a pen after I print the documents: sign_after_printing
1488
1523
  show if:
1489
1524
  code: |
@@ -1493,7 +1528,7 @@ fields:
1493
1528
  input type: radio
1494
1529
  choices:
1495
1530
  - On this device: this_device
1496
- - With a typed signature, like "${ al_typed_signature_prefix }${ users[0] }": typed_signature
1531
+ - With a typed signature, like "${ al_typed_signature_prefix }${ slash_s_example_name }": typed_signature
1497
1532
  - On the paper with a pen after I print the documents: sign_after_printing
1498
1533
  show if:
1499
1534
  code: |
@@ -0,0 +1,27 @@
1
+ ---
2
+ include:
3
+ - assembly_line.yml
4
+ ---
5
+ mandatory: True
6
+ code: |
7
+ preview_screen
8
+ final_screen
9
+ ---
10
+ question: |
11
+ Here is what it looks like unsigned
12
+ subquestion: |
13
+ ${ test_if_final_attachment.as_pdf(key="preview") }
14
+ continue button field: preview_screen
15
+ ---
16
+ question: |
17
+ Here is what it looks like signed
18
+ subquestion: |
19
+ ${ test_if_final_attachment.as_pdf(key="final") }
20
+ event: final_screen
21
+ ---
22
+ objects:
23
+ - test_if_final_attachment: ALDocument.using(title="test_if_final", filename="test_if_final")
24
+ ---
25
+ attachment:
26
+ variable name: test_if_final_attachment[i]
27
+ docx template file: test_if_final.docx
@@ -301,18 +301,24 @@ def get_interview_metadata(
301
301
  Returns:
302
302
  Dict[str, Any]: The metadata associated with the interview
303
303
  """
304
- conn = variables_snapshot_connection()
305
- with conn.cursor() as cur:
306
- query = "select data from jsonstorage where filename=%(filename)s and tags=%(tags)s and key=%(session_id)s"
307
- cur.execute(
308
- query,
304
+ sql = text(
305
+ """
306
+ SELECT data
307
+ FROM jsonstorage
308
+ WHERE filename = :filename
309
+ AND tags = :tags
310
+ AND key = :session_id
311
+ """
312
+ )
313
+ with db.connect() as con:
314
+ row = con.execute(
315
+ sql,
309
316
  {"filename": filename, "tags": metadata_key_name, "session_id": session_id},
310
- )
311
- val = cur.fetchone()
312
- conn.close()
313
- if val and len(val):
314
- return val[0] # cur.fetchone() returns a tuple
315
- return val or {}
317
+ ).fetchone()
318
+
319
+ if row:
320
+ return row[0] # row is a RowMapping/tuple; data is column 0
321
+ return {}
316
322
 
317
323
 
318
324
  def get_saved_interview_list(
@@ -1165,13 +1171,13 @@ def rename_interview_answers(
1165
1171
 
1166
1172
  If exception is raised in set_session_variables, this will silently fail but log the error.
1167
1173
  """
1168
- existing_metadata = get_interview_metadata(
1169
- filename, session_id, metadata_key_name=metadata_key_name
1170
- )
1171
- existing_metadata["title"] = new_name
1172
- set_interview_metadata(
1173
- filename, session_id, existing_metadata, metadata_key_name=metadata_key_name
1174
+ update_session_metadata(
1175
+ filename,
1176
+ session_id,
1177
+ {"title": new_name},
1178
+ metadata_key_name=metadata_key_name,
1174
1179
  )
1180
+
1175
1181
  if session_id == current_context().session:
1176
1182
  set_parts(subtitle=new_name)
1177
1183
  else:
@@ -1614,7 +1620,6 @@ def get_filenames_having_sessions(
1614
1620
  {"admin", "developer"}
1615
1621
  )
1616
1622
 
1617
- conn = variables_snapshot_connection()
1618
1623
  if user_id is None:
1619
1624
  if user_logged_in():
1620
1625
  user_id = user_info().id
@@ -1624,37 +1629,26 @@ def get_filenames_having_sessions(
1624
1629
 
1625
1630
  if user_id == "all":
1626
1631
  if user_has_privilege(global_search_allowed_roles):
1627
- user_id = None
1632
+ user_id = None # unrestricted query
1628
1633
  elif user_logged_in():
1629
- user_id = user_info().id
1634
+ user_id = user_info().id # downgrade to self
1630
1635
  log(
1631
- f"User {user_info().email} does not have permission to list interview sessions belonging to other users"
1636
+ f"User {user_info().email} lacks permission to list sessions for other users"
1632
1637
  )
1633
1638
  else:
1634
1639
  log("Asked to get interview list for user that is not logged in")
1635
1640
  return []
1636
1641
 
1637
- try:
1638
- with conn.cursor(cursor_factory=DictCursor) as cur:
1639
- if user_id is None:
1640
- query = """
1641
- SELECT DISTINCT(filename) AS filename
1642
- FROM userdict
1643
- """
1644
- cur.execute(query)
1645
- else:
1646
- query = """
1647
- SELECT DISTINCT(filename) AS filename
1648
- FROM userdict
1649
- WHERE (%(user_id)s is null OR user_id = %(user_id)s)
1650
- """
1651
- cur.execute(query, {"user_id": user_id})
1642
+ sql_all = text("SELECT DISTINCT filename FROM userdict")
1643
+ sql_user = text("SELECT DISTINCT filename FROM userdict WHERE user_id = :user_id")
1652
1644
 
1653
- results = [record["filename"] for record in cur]
1654
- finally:
1655
- conn.close()
1645
+ with db.connect() as conn:
1646
+ if user_id is None:
1647
+ rows = conn.execute(sql_all).mappings().all()
1648
+ else:
1649
+ rows = conn.execute(sql_user, {"user_id": user_id}).mappings().all()
1656
1650
 
1657
- return results
1651
+ return [row["filename"] for row in rows]
1658
1652
 
1659
1653
 
1660
1654
  def get_combined_filename_list(
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 4.0.0
3
+ Version: 4.1.0
4
4
  Home-page: https://courtformsonline.org
5
5
  Author: Suffolk Legal Innovation and Technology Lab
6
6
  Author-email: qsteenhuis@suffolk.edu
7
7
  License: The MIT License (MIT)
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: docassemble.ALToolbox>=0.11.1
10
+ Requires-Dist: docassemble.ALToolbox>=0.12.0
11
11
  Requires-Dist: docassemble.GithubFeedbackForm>=0.4.1.1
12
12
  Dynamic: author
13
13
  Dynamic: author-email
@@ -55,6 +55,7 @@ docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml
55
55
  docassemble/AssemblyLine/data/questions/test_bundle_parity.yml
56
56
  docassemble/AssemblyLine/data/questions/test_catchall.yml
57
57
  docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml
58
+ docassemble/AssemblyLine/data/questions/test_if_final.yml
58
59
  docassemble/AssemblyLine/data/questions/test_preferred_formats.yml
59
60
  docassemble/AssemblyLine/data/questions/test_question_library.yml
60
61
  docassemble/AssemblyLine/data/questions/test_signature.yml
@@ -90,4 +91,5 @@ docassemble/AssemblyLine/data/templates/general_cover_sheet.docx
90
91
  docassemble/AssemblyLine/data/templates/sample_word_template.docx
91
92
  docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx
92
93
  docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf
93
- docassemble/AssemblyLine/data/templates/test_catchall.docx
94
+ docassemble/AssemblyLine/data/templates/test_catchall.docx
95
+ docassemble/AssemblyLine/data/templates/test_if_final.docx
@@ -1,2 +1,2 @@
1
- docassemble.ALToolbox>=0.11.1
1
+ docassemble.ALToolbox>=0.12.0
2
2
  docassemble.GithubFeedbackForm>=0.4.1.1
@@ -44,7 +44,7 @@ def find_package_data(where='.', package='', exclude=standard_exclude, exclude_d
44
44
  return out
45
45
 
46
46
  setup(name='docassemble.AssemblyLine',
47
- version='4.0.0',
47
+ version='4.1.0',
48
48
  description=(''),
49
49
  long_description='# Suffolk LIT Lab Document Assembly Line\r\n\r\n[![PyPI version](https://badge.fury.io/py/docassemble-AssemblyLine.svg)](https://badge.fury.io/py/docassemble-AssemblyLine)\r\n\r\n<img src="https://user-images.githubusercontent.com/7645641/142245862-c2eb02ab-3090-4e97-9653-bb700bf4c54d.png" alt="drawing" width="300" alt="work together" style="align: center;"/>\r\n\r\nThe Assembly Line Project is a collection of volunteers, students, and institutions who joined together\r\nduring the COVID-19 pandemic to help increase access to the court system. Our vision is mobile-friendly,\r\neasy to use **guided** online forms that help empower litigants to access the court remotely.\r\n\r\nOur signature project is [CourtFormsOnline.org](https://courtformsonline.org).\r\n\r\nWe designed a step-by-step, assembly line style process for automating court forms on top of Docassemble\r\nand built several tools along the way that **you** can use in your home jurisdiction.\r\n\r\nThis package contains **runtime code** and **pre-written questions** to support authoring robust, \r\nconsistent, and attractive Docassemble interviews that help complete court forms.\r\n\r\nRead more on our [documentation page](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/).\r\n\r\n\r\n# Related repositories\r\n\r\n* https://github.com/SuffolkLitLab/docassemble-ALWeaver\r\n* https://github.com/SuffolkLitLab/docassemble-ALMassachusetts\r\n* https://github.com/SuffolkLitLab/docassemble-MassAccess\r\n* https://github.com/SuffolkLitLab/docassemble-ALThemeTemplate\r\n* https://github.com/SuffolkLitLab/EfileProxyServer\r\n\r\n# Documentation\r\n\r\nhttps://suffolklitlab.org/docassemble-AssemblyLine-documentation/\r\n\r\n# Installation\r\n\r\n## Menu-driven installation\r\n\r\nThe recommended installation method is with the [guided installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation).\r\n\r\n## Manual installation\r\n\r\nNormally you do not need to manually install the Assembly Line. Use the [installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation)\r\nif you can. The instructions below are for your optional reference.\r\n\r\nThis package depends on the following configuration changes on your Docassemble server:\r\n\r\n* Ensure that [font-awesome](https://docassemble.org/docs/config.html#default%20icons) is enabled (this may be on by default:\r\n```yaml\r\ndefault icons: font awesome\r\n```\r\n* Add a [Google API key](https://docassemble.org/docs/config.html#google) that has access to:\r\n * Google Places API\r\n * Google Geocoding API\r\n* Add a [VoiceRSS API key](https://docassemble.org/docs/config.html#voicerss)\r\n* Add a [Twilio API key](https://docassemble.org/docs/config.html#twilio) for SMS support\r\n* Add an email account: [Mailgun](https://docassemble.org/docs/config.html#mailgun%20api) or [SendGrid](https://docassemble.org/docs/config.html#sendgrid%20api) recommended for email support\r\n* To show package update time and to enable the feedback form, add a GitHub Private Access token to your config.yml file, like this:\r\n```yaml\r\n# Needs access to create new issues on repositories\r\ngithub issues:\r\n username: "suffolklitlab-issues"\r\n token: "12345"\r\n# Does not need any special access to public repositories \r\ngithub readonly:\r\n username: "suffolklitlab-issues"\r\n password: "45678"\r\n type: "basic"\r\n```\r\n* If you are also using the [Assembly Line Weaver](https://github.com/SuffolkLITLab/docassemble-assemblylinewizard), you may want to set up a [Docassemble API key](https://docassemble.org/docs/api.html#manage_api) in your config.yml file to allow you to install packages automatically, like this:\r\n```yaml\r\ninstall packages api key: 12345\r\n```\r\n\r\n# Migration\r\n\r\nSee [discussion here](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/issues/69)\r\n\r\n\r\n# ALDocument class\r\n\r\n## Purpose\r\n\r\nThe ALDocument class is a small utility library that makes it simpler to use the following features in an interview:\r\n\r\n* Conditional assembly of multiple, optional documents that are triggered in different ways in your interview\r\n* An addendum for PDF files that makes it simple to deal with overflow text\r\n* A customizable download screen that lists the documents in a neat table\r\n* A customizable "send" button that allows the user to email the final forms to a location of their choice\r\n\r\nHere is a small snippet that you can copy and modify that shows how to use the most important features of the ALDocument class.\r\n\r\n```\r\n---\r\nobjects:\r\n - CRA_Motion_to_Dismiss_attachment: ALDocument.using(filename="CRA_Motion_to_Dismiss", title="Motion to Dismiss CRA", enabled=True, has_addendum=True, default_overflow_message="[See addendum]") \r\n---\r\nobjects:\r\n - al_user_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n - al_court_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n---\r\ngeneric object: ALDocument\r\nattachment:\r\n variable name: x.addendum\r\n docx template file: docx_addendum.docx\r\n---\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].overflow_trigger = 640\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].label = "Reasons for request"\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields.gathered = True\r\n \r\n---\r\nattachment:\r\n variable name: CRA_Motion_to_Dismiss_attachment[i]\r\n name: CRA Motion to Dismiss\r\n filename: CRA_Motion_to_Dismiss\r\n skip undefined: True\r\n pdf template file: CRA_Motion_to_Dismiss.pdf\r\n fields: \r\n - "court_county": ${ trial_court.address.county }\r\n - "docket_number": ${ docket_number }\r\n - "user_signature": ${ users[0].signature_if_final(i) }\r\n - "signature_date": ${ signature_date }\r\n```\r\n\r\nIt is very common to have a *contingent* document in ALDocument. If your document is contingent, remove the `enabled=True` from the object declaration, and use\r\nsome other method to "turn on" the attachment.\r\n\r\nE.g.,\r\n\r\n```\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.enabled = condition1 and condition2\r\n```\r\n\r\n# Changelog\r\n\r\nSee [CHANGELOG.MD](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/blob/main/CHANGELOG.md)\r\n',
50
50
  long_description_content_type='text/markdown',
@@ -53,7 +53,7 @@ setup(name='docassemble.AssemblyLine',
53
53
  license='The MIT License (MIT)',
54
54
  url='https://courtformsonline.org',
55
55
  packages=find_namespace_packages(),
56
- install_requires=['docassemble.ALToolbox>=0.11.1', 'docassemble.GithubFeedbackForm>=0.4.1.1'],
56
+ install_requires=['docassemble.ALToolbox>=0.12.0', 'docassemble.GithubFeedbackForm>=0.4.1.1'],
57
57
  zip_safe=False,
58
58
  package_data=find_package_data(where='docassemble/AssemblyLine/', package='docassemble.AssemblyLine'),
59
59
  )
@@ -1 +0,0 @@
1
- __version__ = '4.0.0'