docassemble.AssemblyLine 4.1.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.1.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-4.2.0}/PKG-INFO +1 -1
- docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/__init__.py +1 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_courts.py +12 -11
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_general.py +58 -47
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_document.yml +2 -2
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/aldocument.js +24 -3
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/sessions.py +5 -5
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_al_general.py +151 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +1 -1
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/setup.py +1 -1
- docassemble_assemblyline-4.1.0/docassemble/AssemblyLine/__init__.py +0 -1
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/LICENSE +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/MANIFEST.in +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/README.md +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/al_document.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/custom_jinja_filters.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/ql_namechange.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_catchall.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_if_final.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_preferred_formats.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/questions/test_signature.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_catchall.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/data/templates/test_if_final.docx +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/language.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/py.typed +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/requirements.txt +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/sign.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/test_language.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/__init__.py +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/requires.txt +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/pyproject.toml +0 -0
- {docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/setup.cfg +0 -0
|
@@ -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.
|
|
@@ -1113,6 +1114,7 @@ class ALIndividual(Individual):
|
|
|
1113
1114
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1114
1115
|
suffix_choices: Optional[Union[List[str], Callable]] = None,
|
|
1115
1116
|
title_options: Optional[Union[List[str], Callable]] = None,
|
|
1117
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1116
1118
|
) -> List[Dict[str, str]]:
|
|
1117
1119
|
"""
|
|
1118
1120
|
Generates suitable field prompts for a name based on the type of entity (person or business)
|
|
@@ -1132,6 +1134,7 @@ class ALIndividual(Individual):
|
|
|
1132
1134
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
1133
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`.
|
|
1134
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.
|
|
1135
1138
|
|
|
1136
1139
|
Returns:
|
|
1137
1140
|
List[Dict[str, str]]: A list of dictionaries where each dictionary contains field prompt details.
|
|
@@ -1195,6 +1198,17 @@ class ALIndividual(Individual):
|
|
|
1195
1198
|
if show_if:
|
|
1196
1199
|
for field in fields:
|
|
1197
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
|
+
|
|
1198
1212
|
return fields
|
|
1199
1213
|
elif person_or_business == "business":
|
|
1200
1214
|
fields = [
|
|
@@ -1205,6 +1219,17 @@ class ALIndividual(Individual):
|
|
|
1205
1219
|
]
|
|
1206
1220
|
if show_if:
|
|
1207
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
|
+
|
|
1208
1233
|
return fields
|
|
1209
1234
|
else:
|
|
1210
1235
|
# Note: the labels are template block objects: if they are keys,
|
|
@@ -1272,6 +1297,12 @@ class ALIndividual(Individual):
|
|
|
1272
1297
|
for field in fields:
|
|
1273
1298
|
if field["field"] in maxlengths:
|
|
1274
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
|
+
|
|
1275
1306
|
return fields
|
|
1276
1307
|
|
|
1277
1308
|
def address_fields(
|
|
@@ -1323,6 +1354,7 @@ class ALIndividual(Individual):
|
|
|
1323
1354
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1324
1355
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1325
1356
|
choices: Optional[Union[List[Dict[str, str]], Callable]] = None,
|
|
1357
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1326
1358
|
) -> List[Dict[str, str]]:
|
|
1327
1359
|
"""
|
|
1328
1360
|
Generate fields for capturing gender information, including a
|
|
@@ -1333,6 +1365,7 @@ class ALIndividual(Individual):
|
|
|
1333
1365
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1334
1366
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
1335
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.
|
|
1336
1369
|
|
|
1337
1370
|
Returns:
|
|
1338
1371
|
List[Dict[str, str]]: A list of dictionaries with field prompts for gender.
|
|
@@ -1376,13 +1409,18 @@ class ALIndividual(Individual):
|
|
|
1376
1409
|
if field["field"] in maxlengths:
|
|
1377
1410
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1378
1411
|
|
|
1412
|
+
if required:
|
|
1413
|
+
for field in fields:
|
|
1414
|
+
if field["field"] in required:
|
|
1415
|
+
field["required"] = required[field["field"]]
|
|
1416
|
+
|
|
1379
1417
|
return fields
|
|
1380
1418
|
|
|
1381
1419
|
def pronoun_fields(
|
|
1382
1420
|
self,
|
|
1383
1421
|
show_help=False,
|
|
1384
1422
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1385
|
-
required: bool = False,
|
|
1423
|
+
required: Union[bool, Dict[str, bool]] = False,
|
|
1386
1424
|
shuffle: bool = False,
|
|
1387
1425
|
show_unknown: Optional[Union[Literal["guess"], bool]] = "guess",
|
|
1388
1426
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
@@ -1394,7 +1432,7 @@ class ALIndividual(Individual):
|
|
|
1394
1432
|
Args:
|
|
1395
1433
|
show_help (bool): Whether to show additional help text. Defaults to False.
|
|
1396
1434
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1397
|
-
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.
|
|
1398
1436
|
shuffle (bool): Whether to shuffle the order of pronouns. Defaults to False.
|
|
1399
1437
|
show_unknown (Union[Literal["guess"], bool]): Whether to show an "unknown" option. Can be "guess", True, or False. Defaults to "guess".
|
|
1400
1438
|
maxlengths (Dict[str, int], optional): A dictionary of field names and their maximum lengths. Default is None.
|
|
@@ -1428,7 +1466,7 @@ class ALIndividual(Individual):
|
|
|
1428
1466
|
"datatype": "checkboxes",
|
|
1429
1467
|
"choices": shuffled_choices + final_choices,
|
|
1430
1468
|
"none of the above": str(self.pronoun_prefer_not_to_say_label),
|
|
1431
|
-
"required": required,
|
|
1469
|
+
"required": required if isinstance(required, bool) else False,
|
|
1432
1470
|
},
|
|
1433
1471
|
self_described_input,
|
|
1434
1472
|
]
|
|
@@ -1443,6 +1481,12 @@ class ALIndividual(Individual):
|
|
|
1443
1481
|
if field["field"] in maxlengths:
|
|
1444
1482
|
field["maxlength"] = maxlengths[field["field"]]
|
|
1445
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
|
+
|
|
1446
1490
|
return fields
|
|
1447
1491
|
|
|
1448
1492
|
def get_pronouns(self) -> set:
|
|
@@ -1481,6 +1525,7 @@ class ALIndividual(Individual):
|
|
|
1481
1525
|
style: str = "radio",
|
|
1482
1526
|
show_if: Union[str, Dict[str, str], None] = None,
|
|
1483
1527
|
maxlengths: Optional[Dict[str, int]] = None,
|
|
1528
|
+
required: Optional[Dict[str, bool]] = None,
|
|
1484
1529
|
) -> List[Dict[str, str]]:
|
|
1485
1530
|
"""
|
|
1486
1531
|
Generate fields for capturing language preferences.
|
|
@@ -1490,6 +1535,7 @@ class ALIndividual(Individual):
|
|
|
1490
1535
|
style (str): The display style of choices. Defaults to "radio".
|
|
1491
1536
|
show_if (Union[str, Dict[str, str], None]): Condition to determine if the field should be shown. Defaults to None.
|
|
1492
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.
|
|
1493
1539
|
|
|
1494
1540
|
Returns:
|
|
1495
1541
|
List[Dict[str, str]]: A list of dictionaries with field prompts for language preferences.
|
|
@@ -1524,6 +1570,12 @@ class ALIndividual(Individual):
|
|
|
1524
1570
|
for field in fields:
|
|
1525
1571
|
if field["field"] in maxlengths:
|
|
1526
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
|
+
|
|
1527
1579
|
return fields
|
|
1528
1580
|
|
|
1529
1581
|
def language_name(self) -> str:
|
|
@@ -2360,47 +2412,6 @@ def filter_letters(letter_strings: Union[List[str], str]) -> str:
|
|
|
2360
2412
|
# Note: removed "combined_locations" because it is too tightly coupled to MACourts.py right now
|
|
2361
2413
|
|
|
2362
2414
|
|
|
2363
|
-
def fa_icon(
|
|
2364
|
-
icon: str, color: str = "primary", color_css: Optional[str] = None, size: str = "sm"
|
|
2365
|
-
) -> str:
|
|
2366
|
-
"""
|
|
2367
|
-
Return HTML for a font-awesome icon of the specified size and color. You can reference
|
|
2368
|
-
a CSS variable (such as Bootstrap theme color) or a true CSS color reference, such as 'blue' or
|
|
2369
|
-
'#DDDDDD'. Defaults to Bootstrap theme color "primary".
|
|
2370
|
-
|
|
2371
|
-
Args:
|
|
2372
|
-
icon (str): The name of the icon to use. See https://fontawesome.com/icons for a list of icons.
|
|
2373
|
-
color (str): The color of the icon. Defaults to "primary".
|
|
2374
|
-
color_css (Optional[str]): A CSS variable or color reference. Defaults to None.
|
|
2375
|
-
size (str): The size of the icon. Defaults to "sm".
|
|
2376
|
-
|
|
2377
|
-
Returns:
|
|
2378
|
-
str: HTML for the icon.
|
|
2379
|
-
"""
|
|
2380
|
-
if not color and not color_css:
|
|
2381
|
-
return ":" + icon + ":" # Default to letting Docassemble handle it
|
|
2382
|
-
elif color_css:
|
|
2383
|
-
return (
|
|
2384
|
-
'<i class="fa fa-'
|
|
2385
|
-
+ icon
|
|
2386
|
-
+ " fa-"
|
|
2387
|
-
+ size
|
|
2388
|
-
+ '" style="color:'
|
|
2389
|
-
+ color_css
|
|
2390
|
-
+ ';"></i>'
|
|
2391
|
-
)
|
|
2392
|
-
else:
|
|
2393
|
-
return (
|
|
2394
|
-
'<i class="fa fa-'
|
|
2395
|
-
+ icon
|
|
2396
|
-
+ " fa-"
|
|
2397
|
-
+ size
|
|
2398
|
-
+ '" style="color:var(--'
|
|
2399
|
-
+ color
|
|
2400
|
-
+ ');"></i>'
|
|
2401
|
-
)
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
2415
|
def is_sms_enabled() -> bool:
|
|
2405
2416
|
"""Checks if SMS (Twilio) is enabled on the server. Does not verify that it works.
|
|
2406
2417
|
|
|
@@ -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
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
2
|
+
* Helper function to process multiple email addresses from a string
|
|
3
|
+
* Splits on comma or semicolon and trims whitespace
|
|
4
|
+
*/
|
|
5
|
+
function process_multiple_emails(email_string) {
|
|
6
|
+
if (!email_string || typeof email_string !== 'string') {
|
|
7
|
+
return email_string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Split on comma or semicolon, trim whitespace, and filter out empty strings
|
|
11
|
+
var emails = email_string.split(/[,;]/).map(function(email) {
|
|
12
|
+
return email.trim();
|
|
13
|
+
}).filter(function(email) {
|
|
14
|
+
return email.length > 0;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Return single string if only one email, array if multiple
|
|
18
|
+
return emails.length === 1 ? emails[0] : emails;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* given a docassemble event name, and text ID containing email address(es) and whether
|
|
3
23
|
* or not user wants to send editable files, trigger docassemble event to
|
|
4
|
-
* email an ALDocumentBundle
|
|
24
|
+
* email an ALDocumentBundle. Supports multiple email addresses separated by commas or semicolons.
|
|
5
25
|
*/
|
|
6
26
|
function aldocument_send_action(event_name, wants_editable_id, email_id, template_name="", key="final", preferred_formats=null) {
|
|
7
27
|
var editable = null;
|
|
@@ -18,7 +38,8 @@ function aldocument_send_action(event_name, wants_editable_id, email_id, templat
|
|
|
18
38
|
}
|
|
19
39
|
}
|
|
20
40
|
|
|
21
|
-
var
|
|
41
|
+
var email_raw = $('#' + email_id)[0].value;
|
|
42
|
+
var email = process_multiple_emails(email_raw);
|
|
22
43
|
da_action_perform(event_name, {editable: editable, email: email, key:key, template_name: template_name, preferred_formats: final_formats});
|
|
23
44
|
};
|
|
24
45
|
|
|
@@ -842,13 +842,13 @@ def interview_list_html(
|
|
|
842
842
|
table += f"""
|
|
843
843
|
</td>
|
|
844
844
|
<td>
|
|
845
|
-
<a href="{ url_action(delete_action, filename=answer.get("filename"), session=answer.get("key")) }"><i class="far fa-trash-alt" title="{ delete_label }" aria-hidden="true"></i><span class="sr-only">{ delete_label }</span></a>
|
|
845
|
+
<a href="{ url_action(delete_action, filename=answer.get("filename"), session=answer.get("key")) }"><i class="far fa-trash-alt" title="{ delete_label }" aria-hidden="true"></i><span class="sr-only visually-hidden">{ delete_label }</span></a>
|
|
846
846
|
"""
|
|
847
847
|
if show_view_button:
|
|
848
848
|
table += f"""
|
|
849
849
|
<a target="_blank" href="{ interview_url(i=answer.get("filename"), session=answer.get("key")) }">
|
|
850
850
|
<i class="far fa-eye" aria-hidden="true" title="{ view_label }"></i>
|
|
851
|
-
<span class="sr-only">{ view_label }</span>
|
|
851
|
+
<span class="sr-only visually-hidden">{ view_label }</span>
|
|
852
852
|
</a>
|
|
853
853
|
"""
|
|
854
854
|
table += """
|
|
@@ -1133,7 +1133,7 @@ def session_list_html(
|
|
|
1133
1133
|
<td class="al-progress-box">{ radial_progress(answer) }
|
|
1134
1134
|
</td>
|
|
1135
1135
|
<td>
|
|
1136
|
-
<a class="al-sessions-action-rename" href="{ url_ask_rename }"><i class="fa-solid fa-tag" aria-hidden="true" title="{ rename_label }"></i><span class="sr-only">{ rename_label }</span></a>
|
|
1136
|
+
<a class="al-sessions-action-rename" href="{ url_ask_rename }"><i class="fa-solid fa-tag" aria-hidden="true" title="{ rename_label }"></i><span class="sr-only visually-hidden">{ rename_label }</span></a>
|
|
1137
1137
|
"""
|
|
1138
1138
|
if (
|
|
1139
1139
|
get_config("assembly line", {}).get("enable answer sets")
|
|
@@ -1141,11 +1141,11 @@ def session_list_html(
|
|
|
1141
1141
|
):
|
|
1142
1142
|
table += f"""
|
|
1143
1143
|
|
|
1144
|
-
<a class="al-sessions-actions-clone" href="{ url_ask_copy }"><i class="fa-regular fa-clone" aria-hidden="true" title="{clone_label}"></i><span class="sr-only">{ clone_label }</span></a>
|
|
1144
|
+
<a class="al-sessions-actions-clone" href="{ url_ask_copy }"><i class="fa-regular fa-clone" aria-hidden="true" title="{clone_label}"></i><span class="sr-only visually-hidden">{ clone_label }</span></a>
|
|
1145
1145
|
"""
|
|
1146
1146
|
table += f"""
|
|
1147
1147
|
|
|
1148
|
-
<a href="{ url_ask_delete }" class="text-danger al-delete-session"><i class="far fa-trash-alt text-danger" title="{ delete_label }" aria-hidden="true"></i><span class="sr-only">{ delete_label }</span></a>
|
|
1148
|
+
<a href="{ url_ask_delete }" class="text-danger al-delete-session"><i class="far fa-trash-alt text-danger" title="{ delete_label }" aria-hidden="true"></i><span class="sr-only visually-hidden">{ delete_label }</span></a>
|
|
1149
1149
|
</td>
|
|
1150
1150
|
"""
|
|
1151
1151
|
table += "</tr>"
|
|
@@ -462,6 +462,157 @@ class TestALIndividual(unittest.TestCase):
|
|
|
462
462
|
self.assertEqual(self.individual.name_short(), "Johnny's Sandwiches")
|
|
463
463
|
self.assertEqual(str(self.individual), "Johnny's Sandwiches")
|
|
464
464
|
|
|
465
|
+
def test_name_fields_required(self):
|
|
466
|
+
"""Test the required parameter for name_fields method"""
|
|
467
|
+
self.individual.instanceName = "test_individual"
|
|
468
|
+
self.individual.first_name_label = "First name"
|
|
469
|
+
self.individual.middle_name_label = "Middle name"
|
|
470
|
+
self.individual.last_name_label = "Last name"
|
|
471
|
+
self.individual.suffix_label = "Suffix"
|
|
472
|
+
self.individual.title_label = "Title"
|
|
473
|
+
self.individual.business_name_label = "Business name"
|
|
474
|
+
|
|
475
|
+
# Test without required parameter - middle name should default to False
|
|
476
|
+
fields = self.individual.name_fields(
|
|
477
|
+
person_or_business="person",
|
|
478
|
+
title_choices=["a title"],
|
|
479
|
+
suffix_choices=["Jr.", "Sr."],
|
|
480
|
+
)
|
|
481
|
+
middle_field = None
|
|
482
|
+
for field in fields:
|
|
483
|
+
if "middle" in field["field"]:
|
|
484
|
+
middle_field = field
|
|
485
|
+
break
|
|
486
|
+
self.assertIsNotNone(middle_field)
|
|
487
|
+
self.assertEqual(middle_field["required"], False)
|
|
488
|
+
|
|
489
|
+
# Test with required parameter making middle name required
|
|
490
|
+
fields = self.individual.name_fields(
|
|
491
|
+
person_or_business="person",
|
|
492
|
+
required={"test_individual.name.middle": True},
|
|
493
|
+
title_choices=["a title"],
|
|
494
|
+
suffix_choices=["Jr.", "Sr."],
|
|
495
|
+
)
|
|
496
|
+
middle_field = None
|
|
497
|
+
for field in fields:
|
|
498
|
+
if "middle" in field["field"]:
|
|
499
|
+
middle_field = field
|
|
500
|
+
break
|
|
501
|
+
self.assertIsNotNone(middle_field)
|
|
502
|
+
self.assertEqual(middle_field["required"], True)
|
|
503
|
+
|
|
504
|
+
# Test business case with required parameter
|
|
505
|
+
fields = self.individual.name_fields(
|
|
506
|
+
person_or_business="business",
|
|
507
|
+
required={"test_individual.name.first": True},
|
|
508
|
+
title_choices=["a title"],
|
|
509
|
+
suffix_choices=["Jr.", "Sr."],
|
|
510
|
+
)
|
|
511
|
+
business_field = fields[0]
|
|
512
|
+
self.assertEqual(business_field["required"], True)
|
|
513
|
+
|
|
514
|
+
def test_gender_fields_required(self):
|
|
515
|
+
"""Test the required parameter for gender_fields method"""
|
|
516
|
+
self.individual.instanceName = "test_individual"
|
|
517
|
+
self.individual.gender_female_label = "Female"
|
|
518
|
+
self.individual.gender_male_label = "Female"
|
|
519
|
+
self.individual.gender_nonbinary_label = "Non-binary"
|
|
520
|
+
self.individual.gender_prefer_not_to_say_label = "Prefer not to say"
|
|
521
|
+
self.individual.gender_prefer_self_described_label = "Prefer self-described"
|
|
522
|
+
self.individual.gender_unknown_label = "Unknown"
|
|
523
|
+
self.individual.gender_self_described_label = "Self described"
|
|
524
|
+
self.individual.gender_label = "Gender"
|
|
525
|
+
|
|
526
|
+
# Test without required parameter
|
|
527
|
+
fields = self.individual.gender_fields()
|
|
528
|
+
gender_field = fields[0]
|
|
529
|
+
self.assertNotIn(
|
|
530
|
+
"required", gender_field
|
|
531
|
+
) # Should not have required by default
|
|
532
|
+
|
|
533
|
+
# Test with required parameter
|
|
534
|
+
fields = self.individual.gender_fields(
|
|
535
|
+
required={"test_individual.gender": True}
|
|
536
|
+
)
|
|
537
|
+
gender_field = fields[0]
|
|
538
|
+
self.assertEqual(gender_field["required"], True)
|
|
539
|
+
|
|
540
|
+
# Test key not in required dict - should not change default
|
|
541
|
+
fields = self.individual.gender_fields(required={"other_field": True})
|
|
542
|
+
gender_field = fields[0]
|
|
543
|
+
self.assertNotIn("required", gender_field)
|
|
544
|
+
|
|
545
|
+
def test_pronoun_fields_required(self):
|
|
546
|
+
"""Test the required parameter for pronoun_fields method (both bool and dict)"""
|
|
547
|
+
self.individual.instanceName = "test_individual"
|
|
548
|
+
self.individual.pronoun_prefer_self_described_label = "Something else"
|
|
549
|
+
self.individual.pronoun_unknown_label = "Unknown"
|
|
550
|
+
self.individual.pronoun_self_described_label = "Self described pronouns"
|
|
551
|
+
self.individual.pronouns_label = "Self described pronouns"
|
|
552
|
+
self.individual.pronoun_prefer_not_to_say_label = "Prefer not to say"
|
|
553
|
+
|
|
554
|
+
# Test with boolean required parameter (existing behavior)
|
|
555
|
+
fields = self.individual.pronoun_fields(
|
|
556
|
+
required=True, choices=[{"They/them/theirs": "they/them/theirs"}]
|
|
557
|
+
)
|
|
558
|
+
pronoun_field = fields[0]
|
|
559
|
+
self.assertEqual(pronoun_field["required"], True)
|
|
560
|
+
|
|
561
|
+
# Test with boolean required parameter = False
|
|
562
|
+
fields = self.individual.pronoun_fields(
|
|
563
|
+
required=False, choices=[{"They/them/theirs": "they/them/theirs"}]
|
|
564
|
+
)
|
|
565
|
+
pronoun_field = fields[0]
|
|
566
|
+
self.assertEqual(pronoun_field["required"], False)
|
|
567
|
+
|
|
568
|
+
# Test with dictionary required parameter (new behavior)
|
|
569
|
+
fields = self.individual.pronoun_fields(
|
|
570
|
+
required={"test_individual.pronouns": True},
|
|
571
|
+
choices=[{"They/them/theirs": "they/them/theirs"}],
|
|
572
|
+
)
|
|
573
|
+
pronoun_field = fields[0]
|
|
574
|
+
self.assertEqual(pronoun_field["required"], True)
|
|
575
|
+
|
|
576
|
+
# Test with dictionary required parameter for different field
|
|
577
|
+
fields = self.individual.pronoun_fields(
|
|
578
|
+
required={"test_individual.pronouns_self_described": True},
|
|
579
|
+
choices=[{"They/them/theirs": "they/them/theirs"}],
|
|
580
|
+
)
|
|
581
|
+
pronoun_field = fields[0]
|
|
582
|
+
self_described_field = fields[1]
|
|
583
|
+
self.assertEqual(
|
|
584
|
+
pronoun_field["required"],
|
|
585
|
+
False,
|
|
586
|
+
) # First field should still be False
|
|
587
|
+
self.assertEqual(self_described_field["required"], True)
|
|
588
|
+
|
|
589
|
+
def test_language_fields_required(self):
|
|
590
|
+
"""Test the required parameter for language_fields method"""
|
|
591
|
+
self.individual.instanceName = "test_individual"
|
|
592
|
+
self.individual.language_other_label = "Other language"
|
|
593
|
+
self.individual.language_label = "Language"
|
|
594
|
+
|
|
595
|
+
# Test without required parameter
|
|
596
|
+
fields = self.individual.language_fields()
|
|
597
|
+
language_field = fields[0]
|
|
598
|
+
self.assertNotIn(
|
|
599
|
+
"required", language_field
|
|
600
|
+
) # Should not have required by default
|
|
601
|
+
|
|
602
|
+
# Test with required parameter
|
|
603
|
+
fields = self.individual.language_fields(
|
|
604
|
+
required={"test_individual.language": True}
|
|
605
|
+
)
|
|
606
|
+
language_field = fields[0]
|
|
607
|
+
self.assertEqual(language_field["required"], True)
|
|
608
|
+
|
|
609
|
+
# Test other language field
|
|
610
|
+
fields = self.individual.language_fields(
|
|
611
|
+
required={"test_individual.language_other": False}
|
|
612
|
+
)
|
|
613
|
+
other_field = fields[1]
|
|
614
|
+
self.assertEqual(other_field["required"], False)
|
|
615
|
+
|
|
465
616
|
|
|
466
617
|
class test_get_visible_al_nav_items(unittest.TestCase):
|
|
467
618
|
def test_case_1(self):
|
|
@@ -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.
|
|
47
|
+
version='4.2.0',
|
|
48
48
|
description=(''),
|
|
49
49
|
long_description='# Suffolk LIT Lab Document Assembly Line\r\n\r\n[](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',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '4.1.0'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
{docassemble_assemblyline-4.1.0 → docassemble_assemblyline-4.2.0}/docassemble/AssemblyLine/sign.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|