docassemble.AssemblyLine 4.0.0__tar.gz → 4.2.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.
- {docassemble_assemblyline-4.0.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-4.2.0}/PKG-INFO +2 -2
- docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/__init__.py +1 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_courts.py +12 -11
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_general.py +97 -48
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/custom_jinja_filters.py +112 -2
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_document.yml +2 -2
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +39 -4
- docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/data/questions/test_if_final.yml +27 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/aldocument.js +24 -3
- docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/data/templates/test_if_final.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/sessions.py +39 -45
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_al_general.py +151 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +2 -2
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +3 -1
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/requires.txt +1 -1
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/setup.py +2 -2
- docassemble_assemblyline-4.0.0/docassemble/AssemblyLine/__init__.py +0 -1
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/LICENSE +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/MANIFEST.in +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/README.md +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_document.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_namechange.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_catchall.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_preferred_formats.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_signature.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_catchall.docx +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/language.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/py.typed +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/requirements.txt +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/sign.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_language.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble/__init__.py +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/pyproject.toml +0 -0
- {docassemble_assemblyline-4.0.0 → docassemble_assemblyline-4.2.0}/setup.cfg +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docassemble.AssemblyLine
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.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.
|
|
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.2.0'
|
|
@@ -3,7 +3,7 @@ Package for a very simple / MVP list of courts that is mostly signature compatib
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from typing import Any, Callable, Dict, List, Mapping, Optional, Union, Set
|
|
6
|
+
from typing import Any, Callable, Dict, List, Mapping, Optional, Union, Set, Tuple
|
|
7
7
|
import pandas as pd
|
|
8
8
|
import docassemble.base.functions
|
|
9
9
|
from docassemble.base.util import (
|
|
@@ -238,12 +238,12 @@ class ALCourtLoader(DAObject):
|
|
|
238
238
|
# Only solution I can think of would require court database owners to assign each court a unique ID
|
|
239
239
|
# and something that triggers recalculating the court address/etc info.
|
|
240
240
|
|
|
241
|
-
def all_courts(self) -> List[
|
|
241
|
+
def all_courts(self) -> List[Tuple[int, str]]:
|
|
242
242
|
"""
|
|
243
243
|
Return a list of all courts in the spreadsheet.
|
|
244
244
|
|
|
245
245
|
Returns:
|
|
246
|
-
List[
|
|
246
|
+
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
|
|
247
247
|
"""
|
|
248
248
|
return self.filter_courts(None)
|
|
249
249
|
|
|
@@ -329,13 +329,14 @@ class ALCourtLoader(DAObject):
|
|
|
329
329
|
display_column: str = "name",
|
|
330
330
|
search_string: Optional[str] = None,
|
|
331
331
|
search_columns: Optional[Union[List[str], str]] = None,
|
|
332
|
-
) -> List[
|
|
332
|
+
) -> List[Tuple[int, str]]:
|
|
333
333
|
"""
|
|
334
334
|
Retrieve a list of all courts in the specified county.
|
|
335
335
|
|
|
336
336
|
This function fetches courts suitable for displaying as a drop-down or radio button list
|
|
337
|
-
in Docassemble. The results are
|
|
338
|
-
useful for retrieving the court's full details later using the as_court() method
|
|
337
|
+
in Docassemble. The results are tuples where the first element is the dataframe index
|
|
338
|
+
(useful for retrieving the court's full details later using the as_court() method) and
|
|
339
|
+
the second element is the display value from the specified display_column.
|
|
339
340
|
|
|
340
341
|
Args:
|
|
341
342
|
county_name (str): Name of the county.
|
|
@@ -346,7 +347,7 @@ class ALCourtLoader(DAObject):
|
|
|
346
347
|
the search_string in a case-insensitive manner. Defaults to None.
|
|
347
348
|
|
|
348
349
|
Returns:
|
|
349
|
-
List[
|
|
350
|
+
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
|
|
350
351
|
"""
|
|
351
352
|
return self.filter_courts(
|
|
352
353
|
court_types=county_name,
|
|
@@ -363,11 +364,11 @@ class ALCourtLoader(DAObject):
|
|
|
363
364
|
display_column: str = "name",
|
|
364
365
|
search_string: Optional[str] = None,
|
|
365
366
|
search_columns: Optional[Union[List[str], str]] = None,
|
|
366
|
-
) -> List[
|
|
367
|
+
) -> List[Tuple[int, str]]:
|
|
367
368
|
"""
|
|
368
|
-
Return a filtered subset of courts represented as a list of
|
|
369
|
+
Return a filtered subset of courts represented as a list of tuples.
|
|
369
370
|
|
|
370
|
-
Each
|
|
371
|
+
Each tuple has the format (index, display_value), where "index" refers to the dataframe index and "display_value"
|
|
371
372
|
is determined by the `display_column`.
|
|
372
373
|
|
|
373
374
|
Args:
|
|
@@ -380,7 +381,7 @@ class ALCourtLoader(DAObject):
|
|
|
380
381
|
the search_string in a case-insensitive manner. Defaults to None.
|
|
381
382
|
|
|
382
383
|
Returns:
|
|
383
|
-
List[
|
|
384
|
+
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
|
|
384
385
|
"""
|
|
385
386
|
df = self._load_courts()
|
|
386
387
|
if court_types:
|
|
@@ -37,6 +37,7 @@ from docassemble.base.util import (
|
|
|
37
37
|
log,
|
|
38
38
|
value,
|
|
39
39
|
)
|
|
40
|
+
from docassemble.ALToolbox.misc import fa_icon
|
|
40
41
|
import random
|
|
41
42
|
import re
|
|
42
43
|
import pycountry
|
|
@@ -802,12 +803,12 @@ class ALPeopleList(DAList):
|
|
|
802
803
|
[person.familiar(**kwargs) for person in self], and_string=word("or")
|
|
803
804
|
)
|
|
804
805
|
|
|
805
|
-
def short_list(self, limit: int, truncate_string: str = ", et
|
|
806
|
-
"""Return a subset of the list, truncated with 'et
|
|
806
|
+
def short_list(self, limit: int, truncate_string: str = ", et al.") -> str:
|
|
807
|
+
"""Return a subset of the list, truncated with 'et al.' if it exceeds a given limit.
|
|
807
808
|
|
|
808
809
|
Args:
|
|
809
810
|
limit (int): The maximum number of items to display before truncating.
|
|
810
|
-
truncate_string (str, optional): The string to append when truncating. Defaults to ', et
|
|
811
|
+
truncate_string (str, optional): The string to append when truncating. Defaults to ', et al.'.
|
|
811
812
|
|
|
812
813
|
Returns:
|
|
813
814
|
str: Formatted string of names, truncated if needed.
|
|
@@ -958,6 +959,14 @@ class ALIndividual(Individual):
|
|
|
958
959
|
) -> str:
|
|
959
960
|
"""Fetches and formats the phone numbers of the individual.
|
|
960
961
|
|
|
962
|
+
Supports the following attributes:
|
|
963
|
+
|
|
964
|
+
- `mobile_number`: Mobile phone number
|
|
965
|
+
- `phone_number`: Other phone number
|
|
966
|
+
- `work_number`: Work phone number
|
|
967
|
+
- `other_number`: Any other phone number
|
|
968
|
+
- `home_number`: Home phone number (if applicable)
|
|
969
|
+
|
|
961
970
|
Args:
|
|
962
971
|
country (str, optional): The country for phone number formatting. Defaults to the country of the docassemble server.
|
|
963
972
|
show_impounded (bool): If True, shows the phone numbers even if impounded. Defaults to False.
|
|
@@ -986,6 +995,36 @@ class ALIndividual(Individual):
|
|
|
986
995
|
nums.append({fmt_number: "other"})
|
|
987
996
|
else:
|
|
988
997
|
nums.append({self.phone_number: "other"})
|
|
998
|
+
if hasattr(self, "work_number") and self.work_number:
|
|
999
|
+
fmt_number = None
|
|
1000
|
+
try:
|
|
1001
|
+
fmt_number = phone_number_formatted(self.work_number, country=country)
|
|
1002
|
+
except:
|
|
1003
|
+
fmt_number = None
|
|
1004
|
+
if fmt_number:
|
|
1005
|
+
nums.append({fmt_number: "work"})
|
|
1006
|
+
else:
|
|
1007
|
+
nums.append({self.work_number: "work"})
|
|
1008
|
+
if hasattr(self, "other_number") and self.other_number:
|
|
1009
|
+
fmt_number = None
|
|
1010
|
+
try:
|
|
1011
|
+
fmt_number = phone_number_formatted(self.other_number, country=country)
|
|
1012
|
+
except:
|
|
1013
|
+
fmt_number = None
|
|
1014
|
+
if fmt_number:
|
|
1015
|
+
nums.append({fmt_number: "other"})
|
|
1016
|
+
else:
|
|
1017
|
+
nums.append({self.other_number: "other"})
|
|
1018
|
+
if hasattr(self, "home_number") and self.home_number:
|
|
1019
|
+
fmt_number = None
|
|
1020
|
+
try:
|
|
1021
|
+
fmt_number = phone_number_formatted(self.home_number, country=country)
|
|
1022
|
+
except:
|
|
1023
|
+
fmt_number = None
|
|
1024
|
+
if fmt_number:
|
|
1025
|
+
nums.append({fmt_number: "home"})
|
|
1026
|
+
else:
|
|
1027
|
+
nums.append({self.home_number: "home"})
|
|
989
1028
|
if len(nums) < 1:
|
|
990
1029
|
return ""
|
|
991
1030
|
# Check for impounded phone number
|
|
@@ -1075,6 +1114,7 @@ class ALIndividual(Individual):
|
|
|
1075
1114
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1076
1115
|
suffix_choices: Optional[Union[List[str], Callable]] = None,
|
|
1077
1116
|
title_options: Optional[Union[List[str], Callable]] = None,
|
|
1117
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1078
1118
|
) -> List[Dict[str, str]]:
|
|
1079
1119
|
"""
|
|
1080
1120
|
Generates suitable field prompts for a name based on the type of entity (person or business)
|
|
@@ -1094,6 +1134,7 @@ class ALIndividual(Individual):
|
|
|
1094
1134
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
1095
1135
|
suffix_choices (Union[List[str], Callable], optional): A list of suffix options or a callable to generate suffix options, or overridden by value of global `al_name_suffixes`.
|
|
1096
1136
|
title_options: (Union[List[str], Callable], optional): Deprecated parameter, use `title_choices` instead. If provided, it will be used to set the title choices.
|
|
1137
|
+
required (Dict[str, bool], optional): A dictionary of field names and if they should be required. Default is None.
|
|
1097
1138
|
|
|
1098
1139
|
Returns:
|
|
1099
1140
|
List[Dict[str, str]]: A list of dictionaries where each dictionary contains field prompt details.
|
|
@@ -1157,6 +1198,17 @@ class ALIndividual(Individual):
|
|
|
1157
1198
|
if show_if:
|
|
1158
1199
|
for field in fields:
|
|
1159
1200
|
field["show if"] = show_if
|
|
1201
|
+
|
|
1202
|
+
if maxlengths:
|
|
1203
|
+
for field in fields:
|
|
1204
|
+
if field["field"] in maxlengths:
|
|
1205
|
+
field["maxlength"] = maxlengths[field["field"]]
|
|
1206
|
+
|
|
1207
|
+
if required:
|
|
1208
|
+
for field in fields:
|
|
1209
|
+
if field["field"] in required:
|
|
1210
|
+
field["required"] = required[field["field"]]
|
|
1211
|
+
|
|
1160
1212
|
return fields
|
|
1161
1213
|
elif person_or_business == "business":
|
|
1162
1214
|
fields = [
|
|
@@ -1167,6 +1219,17 @@ class ALIndividual(Individual):
|
|
|
1167
1219
|
]
|
|
1168
1220
|
if show_if:
|
|
1169
1221
|
fields[0]["show if"] = show_if
|
|
1222
|
+
|
|
1223
|
+
if maxlengths:
|
|
1224
|
+
for field in fields:
|
|
1225
|
+
if field["field"] in maxlengths:
|
|
1226
|
+
field["maxlength"] = maxlengths[field["field"]]
|
|
1227
|
+
|
|
1228
|
+
if required:
|
|
1229
|
+
for field in fields:
|
|
1230
|
+
if field["field"] in required:
|
|
1231
|
+
field["required"] = required[field["field"]]
|
|
1232
|
+
|
|
1170
1233
|
return fields
|
|
1171
1234
|
else:
|
|
1172
1235
|
# Note: the labels are template block objects: if they are keys,
|
|
@@ -1234,6 +1297,12 @@ class ALIndividual(Individual):
|
|
|
1234
1297
|
for field in fields:
|
|
1235
1298
|
if field["field"] in maxlengths:
|
|
1236
1299
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1300
|
+
|
|
1301
|
+
if required:
|
|
1302
|
+
for field in fields:
|
|
1303
|
+
if field["field"] in required:
|
|
1304
|
+
field["required"] = required[field["field"]]
|
|
1305
|
+
|
|
1237
1306
|
return fields
|
|
1238
1307
|
|
|
1239
1308
|
def address_fields(
|
|
@@ -1285,6 +1354,7 @@ class ALIndividual(Individual):
|
|
|
1285
1354
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1286
1355
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1287
1356
|
choices: Optional[Union[List[Dict[str, str]], Callable]] = None,
|
|
1357
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1288
1358
|
) -> List[Dict[str, str]]:
|
|
1289
1359
|
"""
|
|
1290
1360
|
Generate fields for capturing gender information, including a
|
|
@@ -1295,6 +1365,7 @@ class ALIndividual(Individual):
|
|
|
1295
1365
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1296
1366
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
1297
1367
|
choices (Optional[Union[List[Dict[str, str]], Callable]]): A list of choices of genders to use in the prompts, or a callable that returns such a list. Default set of choices includes male, female, nonbinary, prefer-not-to-say, self-described, and unknown.
|
|
1368
|
+
required (Dict[str, bool], optional): A dictionary of field names and if they should be required. Default is None.
|
|
1298
1369
|
|
|
1299
1370
|
Returns:
|
|
1300
1371
|
List[Dict[str, str]]: A list of dictionaries with field prompts for gender.
|
|
@@ -1338,13 +1409,18 @@ class ALIndividual(Individual):
|
|
|
1338
1409
|
if field["field"] in maxlengths:
|
|
1339
1410
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1340
1411
|
|
|
1412
|
+
if required:
|
|
1413
|
+
for field in fields:
|
|
1414
|
+
if field["field"] in required:
|
|
1415
|
+
field["required"] = required[field["field"]]
|
|
1416
|
+
|
|
1341
1417
|
return fields
|
|
1342
1418
|
|
|
1343
1419
|
def pronoun_fields(
|
|
1344
1420
|
self,
|
|
1345
1421
|
show_help=False,
|
|
1346
1422
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1347
|
-
required: bool = False,
|
|
1423
|
+
required: Union[bool, Dict[str, bool]] = False,
|
|
1348
1424
|
shuffle: bool = False,
|
|
1349
1425
|
show_unknown: Optional[Union[Literal["guess"], bool]] = "guess",
|
|
1350
1426
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
@@ -1356,7 +1432,7 @@ class ALIndividual(Individual):
|
|
|
1356
1432
|
Args:
|
|
1357
1433
|
show_help (bool): Whether to show additional help text. Defaults to False.
|
|
1358
1434
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1359
|
-
required (bool): Whether the field is required. Defaults to False.
|
|
1435
|
+
required (Union[bool, Dict[str, bool]]): Whether the field is required. Can be a boolean (applies to all fields) or a dictionary of field names and if they should be required. Defaults to False.
|
|
1360
1436
|
shuffle (bool): Whether to shuffle the order of pronouns. Defaults to False.
|
|
1361
1437
|
show_unknown (Union[Literal["guess"], bool]): Whether to show an "unknown" option. Can be "guess", True, or False. Defaults to "guess".
|
|
1362
1438
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
@@ -1390,7 +1466,7 @@ class ALIndividual(Individual):
|
|
|
1390
1466
|
"datatype": "checkboxes",
|
|
1391
1467
|
"choices": shuffled_choices + final_choices,
|
|
1392
1468
|
"none of the above": str(self.pronoun_prefer_not_to_say_label),
|
|
1393
|
-
"required": required,
|
|
1469
|
+
"required": required if isinstance(required, bool) else False,
|
|
1394
1470
|
},
|
|
1395
1471
|
self_described_input,
|
|
1396
1472
|
]
|
|
@@ -1405,6 +1481,12 @@ class ALIndividual(Individual):
|
|
|
1405
1481
|
if field["field"] in maxlengths:
|
|
1406
1482
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1407
1483
|
|
|
1484
|
+
# Handle dictionary-based required parameter
|
|
1485
|
+
if isinstance(required, dict):
|
|
1486
|
+
for field in fields:
|
|
1487
|
+
if field["field"] in required:
|
|
1488
|
+
field["required"] = required[field["field"]]
|
|
1489
|
+
|
|
1408
1490
|
return fields
|
|
1409
1491
|
|
|
1410
1492
|
def get_pronouns(self) -> set:
|
|
@@ -1443,6 +1525,7 @@ class ALIndividual(Individual):
|
|
|
1443
1525
|
style: str = "radio",
|
|
1444
1526
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1445
1527
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1528
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1446
1529
|
) -> List[Dict[str, str]]:
|
|
1447
1530
|
"""
|
|
1448
1531
|
Generate fields for capturing language preferences.
|
|
@@ -1452,6 +1535,7 @@ class ALIndividual(Individual):
|
|
|
1452
1535
|
style (str): The display style of choices. Defaults to "radio".
|
|
1453
1536
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1454
1537
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
1538
|
+
required (Dict[str, bool], optional): A dictionary of field names and if they should be required. Default is None.
|
|
1455
1539
|
|
|
1456
1540
|
Returns:
|
|
1457
1541
|
List[Dict[str, str]]: A list of dictionaries with field prompts for language preferences.
|
|
@@ -1486,6 +1570,12 @@ class ALIndividual(Individual):
|
|
|
1486
1570
|
for field in fields:
|
|
1487
1571
|
if field["field"] in maxlengths:
|
|
1488
1572
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1573
|
+
|
|
1574
|
+
if required:
|
|
1575
|
+
for field in fields:
|
|
1576
|
+
if field["field"] in required:
|
|
1577
|
+
field["required"] = required[field["field"]]
|
|
1578
|
+
|
|
1489
1579
|
return fields
|
|
1490
1580
|
|
|
1491
1581
|
def language_name(self) -> str:
|
|
@@ -2322,47 +2412,6 @@ def filter_letters(letter_strings: Union[List[str], str]) -> str:
|
|
|
2322
2412
|
# Note: removed "combined_locations" because it is too tightly coupled to MACourts.py right now
|
|
2323
2413
|
|
|
2324
2414
|
|
|
2325
|
-
def fa_icon(
|
|
2326
|
-
icon: str, color: str = "primary", color_css: Optional[str] = None, size: str = "sm"
|
|
2327
|
-
) -> str:
|
|
2328
|
-
"""
|
|
2329
|
-
Return HTML for a font-awesome icon of the specified size and color. You can reference
|
|
2330
|
-
a CSS variable (such as Bootstrap theme color) or a true CSS color reference, such as 'blue' or
|
|
2331
|
-
'#DDDDDD'. Defaults to Bootstrap theme color "primary".
|
|
2332
|
-
|
|
2333
|
-
Args:
|
|
2334
|
-
icon (str): The name of the icon to use. See https://fontawesome.com/icons for a list of icons.
|
|
2335
|
-
color (str): The color of the icon. Defaults to "primary".
|
|
2336
|
-
color_css (Optional[str]): A CSS variable or color reference. Defaults to None.
|
|
2337
|
-
size (str): The size of the icon. Defaults to "sm".
|
|
2338
|
-
|
|
2339
|
-
Returns:
|
|
2340
|
-
str: HTML for the icon.
|
|
2341
|
-
"""
|
|
2342
|
-
if not color and not color_css:
|
|
2343
|
-
return ":" + icon + ":" # Default to letting Docassemble handle it
|
|
2344
|
-
elif color_css:
|
|
2345
|
-
return (
|
|
2346
|
-
'<i class="fa fa-'
|
|
2347
|
-
+ icon
|
|
2348
|
-
+ " fa-"
|
|
2349
|
-
+ size
|
|
2350
|
-
+ '" style="color:'
|
|
2351
|
-
+ color_css
|
|
2352
|
-
+ ';"></i>'
|
|
2353
|
-
)
|
|
2354
|
-
else:
|
|
2355
|
-
return (
|
|
2356
|
-
'<i class="fa fa-'
|
|
2357
|
-
+ icon
|
|
2358
|
-
+ " fa-"
|
|
2359
|
-
+ size
|
|
2360
|
-
+ '" style="color:var(--'
|
|
2361
|
-
+ color
|
|
2362
|
-
+ ');"></i>'
|
|
2363
|
-
)
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
2415
|
def is_sms_enabled() -> bool:
|
|
2367
2416
|
"""Checks if SMS (Twilio) is enabled on the server. Does not verify that it works.
|
|
2368
2417
|
|
|
@@ -2404,7 +2453,7 @@ def is_phone_or_email(text: str) -> bool:
|
|
|
2404
2453
|
DAValidationError if the string is neither a valid phone number nor a valid email address.
|
|
2405
2454
|
"""
|
|
2406
2455
|
sms_enabled = is_sms_enabled()
|
|
2407
|
-
if re.match("\S+@\S+", text) or (sms_enabled and phone_number_is_valid(text)):
|
|
2456
|
+
if re.match(r"\S+@\S+", text) or (sms_enabled and phone_number_is_valid(text)):
|
|
2408
2457
|
return True
|
|
2409
2458
|
else:
|
|
2410
2459
|
if sms_enabled:
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
# See: https://docassemble.org/docs/documents.html#register_jinja_filter
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
from
|
|
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]]:
|
|
@@ -162,7 +162,7 @@ subquestion: |
|
|
|
162
162
|
This can take a few minutes.
|
|
163
163
|
|
|
164
164
|
<div class="spinner-border text-primary d-flex justify-content-center" role="status">
|
|
165
|
-
<span class="sr-only">Making documents...</span>
|
|
165
|
+
<span class="sr-only visually-hidden">Making documents...</span>
|
|
166
166
|
</div>
|
|
167
167
|
event: al_download_waiting_screen
|
|
168
168
|
reload: True
|
|
@@ -192,7 +192,7 @@ subquestion: |
|
|
|
192
192
|
This can take a few minutes.
|
|
193
193
|
|
|
194
194
|
<div class="spinner-border text-primary d-flex justify-content-center" role="status">
|
|
195
|
-
<span class="sr-only">Generating preview...</span>
|
|
195
|
+
<span class="sr-only visually-hidden">Generating preview...</span>
|
|
196
196
|
</div>
|
|
197
197
|
event: al_preview_waiting_screen
|
|
198
198
|
reload: True
|
|
@@ -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 }${
|
|
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 }${
|
|
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 }${
|
|
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 }${
|
|
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
|