Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Grand calculated summary value sources #1215

Merged
merged 35 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5129aa0
Add return to list params
katie-gardner Sep 20, 2023
a52c217
Grand Calculated Summary inside repeating section
katie-gardner Sep 20, 2023
b528a44
Fix unit tests
katie-gardner Sep 20, 2023
d01a055
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 20, 2023
bd89e2b
Functional tests
katie-gardner Sep 21, 2023
f69fad4
Some additional comments
katie-gardner Sep 21, 2023
a99c108
Use validator branch
katie-gardner Sep 21, 2023
6a5125b
Remove redundant check
katie-gardner Sep 25, 2023
d777d81
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 25, 2023
16bbeb2
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 26, 2023
b806318
Simplify implementation
katie-gardner Sep 26, 2023
41c38cd
Remove list name parameter and add lookup
katie-gardner Sep 26, 2023
2e43704
Remove unnecessary comment
katie-gardner Sep 26, 2023
a482621
Fix test errors
katie-gardner Sep 26, 2023
d4fa3d6
Add support for grand calculated summary value sources
katie-gardner Sep 26, 2023
b0d1a80
Fix typo and formatting
katie-gardner Sep 26, 2023
d2b6d5f
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 27, 2023
f1f9ac6
Merge branch 'grand-calculated-summary-in-repeating-section' into gra…
katie-gardner Sep 27, 2023
4cd24c3
PR comments
katie-gardner Sep 28, 2023
dee5446
Move string method into utilities
katie-gardner Sep 28, 2023
5ced068
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 28, 2023
349b271
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Sep 28, 2023
484c675
Merge branch 'main' into grand-calculated-summary-in-repeating-section
katie-gardner Oct 4, 2023
3dc4617
Fix params not being preserved when section is incomplete
katie-gardner Oct 4, 2023
8870f79
Merge branch 'grand-calculated-summary-in-repeating-section' into gra…
katie-gardner Oct 4, 2023
247996b
Add value source resolver test for GCS
katie-gardner Oct 4, 2023
4c5c043
Restore validator branch
katie-gardner Oct 4, 2023
4d4f15e
Merge branch 'grand-calculated-summary-in-repeating-section' into gra…
katie-gardner Oct 5, 2023
bb3f7bb
Merge branch 'main' into grand-calculated-summary-value-source
katie-gardner Oct 5, 2023
71381dc
Fix test assertions
katie-gardner Oct 5, 2023
e33f43a
Better comments
katie-gardner Oct 6, 2023
e59c176
Merge branch 'main' into grand-calculated-summary-value-source
MebinAbraham Oct 9, 2023
e1d2446
Revert validator branch
katie-gardner Oct 10, 2023
9b56ac9
Merge branch 'main' into grand-calculated-summary-value-source
katie-gardner Oct 11, 2023
40603e5
Merge branch 'main' into grand-calculated-summary-value-source
katie-gardner Oct 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion app/questionnaire/placeholder_transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
from babel.dates import format_datetime
from dateutil.relativedelta import relativedelta
from flask_babel import ngettext
from werkzeug.datastructures import ImmutableDict

from app.questionnaire.questionnaire_schema import QuestionnaireSchema
from app.questionnaire.questionnaire_schema import (
QuestionnaireSchema,
get_calculation_block_ids_for_grand_calculated_summary,
)
from app.questionnaire.rules.operations import DateOffset
from app.questionnaire.rules.operations_helper import OperationHelper
from app.questionnaire.rules.utils import parse_datetime
Expand Down Expand Up @@ -73,6 +77,14 @@ def _get_decimal_limit(self, unresolved_arguments: Mapping) -> int | None:
decimal_limit = self.schema.get_decimal_limit_from_calculated_summaries(
[identifier]
)
elif source == "grand_calculated_summary":
# Type ignore: Validator will have checked the id so the block is guaranteed to exist
grand_calculated_summary_block: ImmutableDict = self.schema.get_block(identifier) # type: ignore
petechd marked this conversation as resolved.
Show resolved Hide resolved
decimal_limit = self.schema.get_decimal_limit_from_calculated_summaries(
get_calculation_block_ids_for_grand_calculated_summary(
grand_calculated_summary_block
)
)

return decimal_limit

Expand Down
18 changes: 9 additions & 9 deletions app/questionnaire/value_source_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,20 +230,20 @@ def _resolve_list_value_source(self, value_source: Mapping) -> int | str | list:

return list(list_model)

def _resolve_calculated_summary_value_source(
def _resolve_summary_with_calculation(
self, value_source: Mapping, *, assess_routing_path: bool
) -> IntOrDecimal | None:
"""Calculates the value for the 'calculation' used by the provided Calculated Summary.
"""Calculates the value for the 'calculation' used by the provided Calculated or Grand Calculated Summary.

The caller is responsible for ensuring the provided Calculated Summary and its answers are on the path,
The caller is responsible for ensuring the provided summary and its components are on the path
or providing routing_path_block_ids when initialising the value source resolver.
"""
calculated_summary_block: ImmutableDict = self.schema.get_block(value_source["identifier"]) # type: ignore

if not self._is_block_on_path(calculated_summary_block["id"]):
summary_block: ImmutableDict = self.schema.get_block(value_source["identifier"]) # type: ignore
if not self._is_block_on_path(summary_block["id"]):
return None

calculation = calculated_summary_block["calculation"]
calculation = summary_block["calculation"]
petechd marked this conversation as resolved.
Show resolved Hide resolved
# the calculation object for the old type of calculated summary block may contain answers_to_calculate instead of operation
if calculation.get("answers_to_calculate"):
operator = self.get_calculation_operator(calculation["calculation_type"])
list_item_id = self._resolve_list_item_id_for_value_source(value_source)
Expand Down Expand Up @@ -319,8 +319,8 @@ def resolve(
) -> ValueSourceEscapedTypes | ValueSourceTypes:
source = value_source["source"]

if source == "calculated_summary":
return self._resolve_calculated_summary_value_source(
if source in {"calculated_summary", "grand_calculated_summary"}:
MebinAbraham marked this conversation as resolved.
Show resolved Hide resolved
return self._resolve_summary_with_calculation(
value_source=value_source, assess_routing_path=True
)
resolve_method_mapping = {
Expand Down

Large diffs are not rendered by default.

248 changes: 248 additions & 0 deletions schemas/test/en/test_grand_calculated_summary_repeating_answers.json
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,9 @@
]
}
},
"summary": {
"show_on_completion": true
},
"groups": [
{
"id": "group-7",
Expand Down Expand Up @@ -1169,6 +1172,251 @@
]
}
}
},
{
"type": "Question",
"id": "internet-breakdown-block",
"question": {
"id": "internet-breakdown-question",
"title": {
"text": "How did you use the {internet_usage} across your devices?",
"placeholders": [
{
"placeholder": "internet_usage",
"transforms": [
{
"transform": "format_unit",
"arguments": {
"value": {
"source": "grand_calculated_summary",
"identifier": "grand-calculated-summary-4"
},
"unit": "digital-gigabyte",
"unit_length": "short"
}
}
]
}
]
},
"type": "Calculated",
"warning": "These answers must add up to the total internet usage",
"calculations": [
{
"calculation_type": "sum",
"value": {
"identifier": "grand-calculated-summary-4",
"source": "grand_calculated_summary"
},
"answers_to_calculate": ["internet-pc", "internet-phone"],
"conditions": ["equals"]
}
],
"answers": [
{
"id": "internet-pc",
"label": "Amount of internet usage via PC",
"mandatory": true,
"type": "Unit",
"unit_length": "short",
"unit": "digital-gigabyte",
"decimal_places": 2
},
{
"id": "internet-phone",
"label": "Amount of internet usage via Phone",
"mandatory": true,
"type": "Unit",
"unit_length": "short",
"unit": "digital-gigabyte",
"decimal_places": 2
}
]
}
}
]
}
]
},
{
"id": "section-7",
"title": "Personal Expenditure",
"enabled": {
"when": {
"==": [
"COMPLETED",
{
"source": "progress",
"selector": "section",
"identifier": "section-6"
}
]
}
},
"summary": {
"show_on_completion": true
},
"groups": [
{
"id": "group-8",
"blocks": [
{
"type": "Question",
"id": "personal-expenditure-block",
"question": {
"id": "personal-expenditure-question",
"title": {
"text": "How much of the {total_expenditure} household expenditure do you contribute personally?",
"placeholders": [
{
"placeholder": "total_expenditure",
"transforms": [
{
"transform": "format_currency",
"arguments": {
"number": {
"identifier": "grand-calculated-summary-5",
"source": "grand_calculated_summary"
}
}
}
]
}
]
},
"type": "General",
"answers": [
{
"id": "personal-expenditure-answer",
"label": "Personal contribution",
"mandatory": true,
"description": "Cannot exceed the total expenditure from section 6",
"type": "Currency",
"currency": "GBP",
"decimal_places": 2,
"maximum": {
"value": {
"identifier": "grand-calculated-summary-5",
"source": "grand_calculated_summary"
}
}
}
]
}
},
{
"type": "Interstitial",
"id": "grand-calculated-summary-piping",
"content": {
"title": "You have provided the following information about household expenditure and internet use.",
"contents": [
{
"list": [
{
"text": "Total household expenditure: <em>{total_expenditure}</em>",
"placeholders": [
{
"placeholder": "total_expenditure",
"transforms": [
{
"transform": "format_currency",
"arguments": {
"number": {
"identifier": "grand-calculated-summary-5",
"source": "grand_calculated_summary"
}
}
}
]
}
]
},
{
"text": "Personal contribution: <em>{personal_contribution}</em>",
"placeholders": [
{
"placeholder": "personal_contribution",
"transforms": [
{
"transform": "format_currency",
"arguments": {
"number": {
"identifier": "personal-expenditure-answer",
"source": "answers"
}
}
}
]
}
]
},
{
"text": "Total internet usage: <em>{internet_usage}</em>",
"placeholders": [
{
"placeholder": "internet_usage",
"transforms": [
{
"transform": "format_unit",
"arguments": {
"value": {
"source": "grand_calculated_summary",
"identifier": "grand-calculated-summary-4"
},
"unit": "digital-gigabyte",
"unit_length": "short"
}
}
]
}
]
},
{
"text": "Usage by phone: <em>{internet_phone}</em>",
"placeholders": [
{
"placeholder": "internet_phone",
"transforms": [
{
"transform": "format_unit",
"arguments": {
"value": {
"source": "answers",
"identifier": "internet-phone"
},
"unit": "digital-gigabyte",
"unit_length": "short"
}
}
]
}
]
},
{
"text": "Usage by PC: <em>{internet_pc}</em>",
"placeholders": [
{
"placeholder": "internet_pc",
"transforms": [
{
"transform": "format_unit",
"arguments": {
"value": {
"source": "answers",
"identifier": "internet-pc"
},
"unit": "digital-gigabyte",
"unit_length": "short"
}
}
]
}
]
}
]
}
]
}
}
]
}
Expand Down
Loading